TypeScript中如何让typeof支持子类?解决MyClass传参报错问题
解决TypeScript中
typeof兼容子类构造函数的问题 首先咱们得搞清楚为什么new MyClass(Dog)会报错。核心问题在于:typeof Animal代表的是泛型类Animal的构造函数类型,而Dog是Animal<Mercedes>的子类,它的构造函数是一个具体的、非泛型的构造函数,两者的类型规则不兼容。
问题根源拆解
先看你定义的MyClass:
export class MyClass { constructor(animalClass: typeof Animal) {}}
这里的typeof Animal对应的构造函数签名本质是:
new <T extends Car>(): Animal<T>
而typeof Dog的构造函数签名是:
new(): Dog // 等价于Animal<Mercedes>
TypeScript不会认为这两个构造函数兼容——前者是需要传入泛型参数的泛型构造器,后者是已经实例化了泛型的具体构造器,类型约束不匹配。
解决方案
我们需要把MyClass的构造参数改成能接受Animal任意子类构造函数的类型,而非严格的typeof Animal,这里有三种常用方案:
方案1:基础兼容的构造函数类型
定义一个返回Animal<Car>子类的构造函数类型,利用TypeScript泛型类的协变规则:
export class MyClass { constructor(animalClass: new () => Animal<Car>) {} }
这样Dog就能正常传入了——因为Dog的实例是Animal<Mercedes>,而Mercedes是Car的子类,Animal<Mercedes>属于Animal<Car>的子类型,完全符合约束。
方案2:保留泛型信息的泛型MyClass
如果需要后续用到子类的具体泛型类型,可以把MyClass也改成泛型:
export class MyClass<T extends Car> { constructor(animalClass: new () => Animal<T>) {} } // 使用时明确泛型类型 let x = new MyClass<Mercedes>(Dog);
这种方式能让MyClass精准感知传入的animalClass对应的Car子类类型,适合需要类型精确性的场景。
方案3:最宽松的构造函数类型
如果不需要严格的类型检查,也可以定义一个极度宽泛的构造函数类型:
type AnimalConstructor = new (...args: any[]) => Animal<any>; export class MyClass { constructor(animalClass: AnimalConstructor) {} }
这种方式几乎不做类型约束,适合快速兼容所有Animal子类的场景。
验证修改后的完整代码
用方案1修改后的完整示例:
export class Car { } export class Mercedes extends Car { } export class Animal<T extends Car> { car: T; } export class Dog extends Animal<Mercedes> { } export class MyClass { constructor(animalClass: new () => Animal<Car>) {} } let x = new MyClass(Dog); // 现在可以正常运行了!
内容的提问来源于stack exchange,提问作者Jelle den Burger
相关产品推荐
相关产品推荐

