如何在TypeScript中构建返回值类型精确的mixin工厂函数
你遇到的报错是因为原有实现对泛型的约束和返回值类型不匹配:当输入参数是抽象构造器时,写死的返回值ConcreteConstructor无法兼容抽象类的类型定义,同时TypeScript无法直接推导匿名子类和泛型T的交叉类型关系。
可行实现方案
// 定义两种构造器类型,兼容普通类和抽象类 type ConcreteConstructor<T = {}> = new (...args: any[]) => T; type AbstractConstructor<T = {}> = abstract new (...args: any[]) => T; type AnyConstructor<T = {}> = ConcreteConstructor<T> | AbstractConstructor<T>; function Unique<T extends AnyConstructor>(BaseClass: T) { // 扩展传入的基类 const ExtendedClass = class extends BaseClass { public readonly uniqueId = Symbol(); }; // 通过条件类型自动推导返回值类型,适配普通类/抽象类两种输入 return ExtendedClass as T extends ConcreteConstructor<infer Instance> ? ConcreteConstructor<Instance & { readonly uniqueId: symbol }> : T extends AbstractConstructor<infer Instance> ? AbstractConstructor<Instance & { readonly uniqueId: symbol }> : never; }
验证效果
无需任何类型断言,即可同时识别基类成员和新增的uniqueId属性:
// 测试普通类 class Dog { constructor(public name: string) {} bark() { return "汪"; } } const UniqueDog = Unique(Dog); const myDog = new UniqueDog("大黄"); // 可正常调用 myDog.name、myDog.bark()、myDog.uniqueId,类型推导全部正确 // 测试抽象类 abstract class Animal { abstract move(): void; age = 0; } const UniqueAnimal = Unique(Animal); // 符合抽象类特性:无法直接 new UniqueAnimal() class Bird extends UniqueAnimal { move() { console.log("飞"); } } const myBird = new Bird(); // 可正常调用 myBird.age、myBird.move()、myBird.uniqueId,类型推导全部正确
该实现完全满足需求:支持扩展任意普通类/抽象类,返回值类型自动保留基类所有类型信息,同时新增uniqueId属性的类型定义,无需额外类型断言。
内容的提问来源于stack exchange,提问作者Dario Scattolini
相关产品推荐
相关产品推荐

