TypeScript中如何引用实现指定接口的类类型?
这个问题问得很关键——TypeScript确实没有内置的Class<T>类型,但我们可以通过自定义构造函数类型来实现你想要的效果,完美适配所有实现指定接口的类。
核心问题解析
首先要明确:接口是TypeScript纯类型层面的概念,编译后会被完全擦除,不存在对应的运行时值,所以typeof IAnInterface会报错(提示你把类型当成了值来用)。而类是有运行时实体的(编译后的构造函数),所以typeof AClassThatImplementsAnInterface能正确拿到它的构造函数类型。
我们需要的是一个泛化的类型,用来描述“所有能创建出IAnInterface实例的类的构造函数”,而不是单个类的类型。
解决方案:自定义构造函数类型
我们可以定义一个通用的构造函数类型,用来代表“能生成T类型实例的任何类”:
// 通用构造函数类型:接受任意参数,返回T类型的实例 type Constructable<T> = new (...args: any[]) => T;
这里的Constructable<IAnInterface>就是你要找的“等价于Class<IAnInterface>”的类型——它会匹配所有实现了IAnInterface的类的构造函数。
应用到你的类型映射场景
把这个自定义类型用到你的IClassTypeMapping中,就能实现你想要的效果:
// 你的接口和实现类 interface IAnInterface { } class AClassThatImplementsAnInterface implements IAnInterface { } class AnotherImpl implements IAnInterface { } // 自定义构造函数类型 type Constructable<T> = new (...args: any[]) => T; // 你的字面量联合类型 type SomeLiteralStringUnion = "foo" | "bar"; // 最终的类型映射 type IClassTypeMapping = { [name in SomeLiteralStringUnion]: Constructable<IAnInterface> }; // 合法的赋值示例 const classMappings: IClassTypeMapping = { foo: AClassThatImplementsAnInterface, bar: AnotherImpl };
TypeScript会自动检查:只有实现了IAnInterface的类才能被赋值到classMappings中,完全符合你的需求。
进阶:限制构造函数参数
如果你的类构造函数有特定的参数要求,还可以调整构造函数类型来精确匹配:
// 定义带特定参数的构造函数类型 type ConstructableWithArgs<T, Args extends any[]> = new (...args: Args) => T; // 要求构造函数必须接受一个string参数 type IAnInterfaceConstructor = ConstructableWithArgs<IAnInterface, [string]>; // 符合要求的类 class ImplWithStringCtor implements IAnInterface { constructor(name: string) {} } // 合法赋值 const validCtor: IAnInterfaceConstructor = ImplWithStringCtor; // 不符合要求的类会触发类型错误 class BadImpl implements IAnInterface { constructor(num: number) {} } const invalidCtor: IAnInterfaceConstructor = BadImpl; // TypeScript会报错:参数类型不匹配
总结
这种方式在TypeScript中是完全可行的,核心是利用TypeScript的函数类型系统,通过new关键字标记构造函数签名,从而抽象出“所有能生成某类型实例的类”的通用类型。
内容的提问来源于stack exchange,提问作者Mohamed Allal

