如何创建符合泛型接口的枚举类映射?TypeScript技术问询
TypeScript泛型工厂模式的类型约束问题
我见过的大多数TypeScript工厂模式都是基于名称与类构造函数的映射实现,简易代码如下:
const myMap = { classOne: ExampleClass, classTwo: AnotherClass } (k: string) => { return new myMap[k] }
我希望升级这种实现——我的类都遵循ExampleClass implements iGenericInterface<T>的形式,但无法正确定义映射的类型约束,让编译器只接受实现了iGenericInterface<T>的类。以下示例中标记***的位置是核心问题点:
export interface iGenericInterface<K> { process(input: K): void } class ExampleClass implements iGenericInterface<string> { process(input: string): void { console.log(input); } } class AnotherClass implements iGenericInterface<number> { process(input: number): void { console.log(input); } } class UnsupportedClass { otherMethod(input: boolean): void { console.log(input); } } enum instantiableClassesEnum { class1, class2, class3 }; type enumValues = keyof typeof instantiableClassesEnum; type logicStore<T> = Record<enumValues, ***iGenericInterface<T>***> const classMap: logicStore<any> = { class1: ExampleClass, class2: AnotherClass, class3: UnsupportedClass, };
我需要编译器对UnsupportedClass报错,同时正常接受其他类。如果把ExampleClass改成实例(比如class1: new ExampleClass()),编译器不会报错,但这样就没法在工厂方法return new myMap[k]中使用这个映射了。
我的最终目标是基于枚举输入创建类,实现如下工厂:
class LogicFactory { static createLogic<T>(logicClass: enumValues): iGenericInterface<T> { return new classMap[logicClass](); } }
解决方案
1. 定义构造函数类型
首先要明确:映射中存储的是类的构造函数,而不是类的实例。先定义一个构造函数类型,用来描述能生成iGenericInterface实例的类:
// 无参构造,返回实现iGenericInterface的实例 type Constructable<T> = new () => T;
2. 修正映射的类型约束
把logicStore的类型改为存储符合要求的构造函数,这样就能过滤掉未实现接口的类:
// 约束映射值为能生成iGenericInterface实例的构造函数 type logicStore = Record<enumValues, Constructable<iGenericInterface<unknown>>>; const classMap: logicStore = { class1: ExampleClass, class2: AnotherClass, // 此处编译器会报错:UnsupportedClass的实例未实现iGenericInterface class3: UnsupportedClass, };
3. 优化工厂方法的类型推断
如果希望工厂方法能根据传入的枚举值自动推断返回的泛型类型(而非手动指定T),可以建立枚举与泛型参数的映射关系:
// 建立枚举值与对应泛型参数的映射 type LogicTypeMap = { [instantiableClassesEnum.class1]: string; [instantiableClassesEnum.class2]: number; }; class LogicFactory { static createLogic<K extends instantiableClassesEnum>( logicClass: K ): iGenericInterface<LogicTypeMap[K]> { // 类型断言确保类型匹配 return new classMap[logicClass]() as iGenericInterface<LogicTypeMap[K]>; } }
调用时编译器会自动推断返回类型:
// 自动推断返回iGenericInterface<string> const logic1 = LogicFactory.createLogic(instantiableClassesEnum.class1); logic1.process("test"); // 正常 // 自动推断返回iGenericInterface<number> const logic2 = LogicFactory.createLogic(instantiableClassesEnum.class2); logic2.process(123); // 正常
内容的提问来源于stack exchange,提问作者redevill
相关产品推荐
相关产品推荐

