打字稿-工厂模式

Typescript - factory pattern

我正在尝试为 MainType 创建工厂。我还想重用已经创建的类型(实际上我需要相同的实例)所以我将它们存储在 ItemFactory.

class BaseType {

}

class MainType extends BaseType {

}

class ItemFactory {
    items: { [type: string]: BaseType } = {};

    get<T extends BaseType>(type: string): T | null {
        let item = this.items[type];

        if (!item) {
            switch (type) {
                case "main-type":
                    item = new MainType();
                    break;
                default:
                    return null;
            }

            this.items[type] = item;
        }

        return item as T;
    }
}

有没有办法简化调用

itemFactory.get<MainType>("main-type"); // current call

// option 1
const resolvedType = itemFactory.get<MainType>();

// option 2
const resolvedType = itemFactory.get("main-type");

我想要选项 1 或选项 2(不需要两者),因此我不必同时传递标识符和类型来正确解析结果类型。

您需要为编译器提供某种传递给 itemFactory.get() 的名称与预期输出类型之间的映射。从名称到类型的映射是 interfaces 最擅长的,因此您可以这样定义一个:

interface NameMap {
  "main-type": MainType;
  // other name-type mappings here
}

然后您将 get() 方法更改为:

  get<K extends keyof NameMap>(type: K): NameMap[K] | null {
    let item = this.items[type];

    if (!item) {
      switch (type) {
        case "main-type":
          item = new MainType();
          break;
        default:
          return null;
      }

      this.items[type] = item;
    }

    return item as NameMap[K];
  }

您将 T extends BaseType 替换为 NameMap[K],其中 K extends keyof NameMap。现在以下 ("option 2") 将起作用:

const resolvedType = itemFactory.get("main-type"); // MainType | null

请注意,您永远不会 "option 1" 工作。当 JS 被发出时,TypeScript 的类型系统得到 erased,所以这个:

itemFactory.get<MainType>();

运行时会变成这样:

itemFactory.get();

并且 that 无法知道要 return 做什么,因为相关信息在代码开始 运行 之前就已经留下了。这是故意的;它是 not a goal of TypeScript 到 "add or rely on run-time type information in programs, or emit different code based on the results of the type system." 相反,TypeScript 应该 "encourage programming patterns that do not require run-time metadata"... 在这种情况下,它意味着使用像字符串 "main-type" 这样的运行时值而不是像这样的设计时类型MainType 跟踪 get() 应该做什么。


好的,希望对您有所帮助。祝你好运!

Link to code