打字稿-工厂模式
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()
的名称与预期输出类型之间的映射。从名称到类型的映射是 interface
s 最擅长的,因此您可以这样定义一个:
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()
应该做什么。
好的,希望对您有所帮助。祝你好运!
我正在尝试为 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()
的名称与预期输出类型之间的映射。从名称到类型的映射是 interface
s 最擅长的,因此您可以这样定义一个:
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()
应该做什么。
好的,希望对您有所帮助。祝你好运!