TypeScript中mixin函数的正确类型定义及报错消除方法问询
TypeScript Mixin 类型报错修复方案
问题复现
现有代码运行逻辑正常,但Mixer.registerMixin调用时触发两类类型错误,核心原因为Mixin类型定义不符合TypeScript泛型约束规则。
错误根源
原Mixin类型声明了两个泛型<T extends BaseClass, U extends T>:
- 泛型
U的实际类型由调用Mixin函数的一侧决定,没有和输入参数做关联 - 实现mixin时返回的是固定扩展的匿名类,无法满足调用方可能传入的任意
U子类型约束,因此触发不兼容报错
修复代码
直接移除多余的U泛型,调整Mixin类型定义即可消除所有报错,完整可运行无错代码如下:
class BaseClass {} type Constructor<T extends BaseClass> = new (...args: any[]) => T; // 修正后Mixin类型:仅保留基类泛型T,返回T的扩展类型构造函数 type Mixin = <T extends BaseClass>(Base: Constructor<T>) => Constructor<T>; class Mixer { private static mixins: Record<string, Mixin> = {}; public static registerMixin(name: string, mixin: Mixin): void { if (!Mixer.mixins[name]) { Mixer.mixins[name] = mixin; } } public static getClass(...mixinNames: Array<string>): Constructor<BaseClass> { let mixedClass = BaseClass; for (const name of mixinNames) { if (Mixer.mixins[name]) { mixedClass = Mixer.mixins[name](mixedClass); } } return mixedClass; } } Mixer.registerMixin('a', Base => class extends Base { public a = '' }); Mixer.registerMixin('b', Base => class extends Base { public b = '' }); Mixer.registerMixin('c', Base => class extends Base { public c = '' }); Mixer.registerMixin('d', Base => class extends Base { public d = '' }); Mixer.registerMixin('e', Base => class extends Base { public e = '' }); console.log(new (Mixer.getClass('a', 'c', 'e'))());
补充说明
如果需要保留mixin扩展属性的类型推导,可以进一步将Mixin改造为带扩展属性声明的泛型类型:
type Mixin<Ext = {}> = <T extends BaseClass>(Base: Constructor<T>) => Constructor<T & Ext>; // 注册带属性类型提示的mixin Mixer.registerMixin('a', (Base => class extends Base { public a = '' }) as Mixin<{a: string}>);
内容的提问来源于stack exchange,提问作者S. Wolf
相关产品推荐
相关产品推荐

