如何定义通用类Mixin函数类型,实现类型安全的混合类构建
实现类型安全的Mixin组合函数
我们需要实现一个mix函数,支持通过const MixedClass2 = mix(BaseNode, [PositionedNodeMixin, NodeChildrenMixin])的方式创建混合类,同时保留pos和children等属性的类型安全性。
现有代码实现
首先是已定义的Mixin和基类代码:
type Constructor = new (...args: any[]) => {}; export const PositionedNodeMixin = <C extends Constructor>(superclass: C) => { return class NodePositionableAbilities extends superclass { pos: string = ""; }; }; export const NodeChildrenMixin = <C extends Constructor>(superclass: C) => { const x = class NodeChildrenAbilities extends superclass { children: Record<string, boolean | undefined> = {}; }; return x; }; class BaseNode { id: string; constructor() { this.id = Math.random().toString(); } }
当前的Mixin调用方式
目前只能通过嵌套调用的方式生成混合类:
const MixedClass = PositionedNodeMixin(NodeChildrenMixin(BaseNode)); const mixedClassInstance = new MixedClass(); console.log(mixedClassInstance.id); console.log(mixedClassInstance.children); console.log(mixedClassInstance.pos);
解决方案:实现mix函数及类型定义
我们需要定义对应的类型,让mix函数支持数组传参并保持类型安全:
类型定义与函数实现
// 定义Mixin的通用类型:接收构造函数,返回新构造函数 type Mixin = <C extends Constructor>(superclass: C) => Constructor & InstanceType<C>; // 递归推导所有Mixin应用后的最终类型 type ApplyMixins<T extends Constructor, M extends Mixin[]> = M extends [infer FirstMixin extends Mixin, ...infer RestMixins extends Mixin[]] ? ApplyMixins<ReturnType<FirstMixin> & T, RestMixins> : T; // 实现mix函数 function mix<T extends Constructor, M extends Mixin[]>( baseClass: T, mixins: [...M] ): ApplyMixins<T, M> { // 依次将每个Mixin应用到基类上 return mixins.reduce((currentClass, mixin) => mixin(currentClass), baseClass) as ApplyMixins<T, M>; }
使用示例
现在可以用数组方式组合Mixin,且所有属性类型都能被正确推导:
const MixedClass2 = mix(BaseNode, [PositionedNodeMixin, NodeChildrenMixin]); const instance2 = new MixedClass2(); console.log(instance2.id); // 类型:string console.log(instance2.pos); // 类型:string console.log(instance2.children);// 类型:Record<string, boolean | undefined>
关键说明
Mixin类型:统一了所有Mixin的结构,确保每个Mixin都符合“接收构造函数并返回新构造函数”的规范。ApplyMixins类型:通过递归遍历Mixin数组,逐个推导应用Mixin后的类型,最终得到包含所有Mixin属性的构造函数类型。mix函数:使用reduce方法依次应用每个Mixin,同时通过类型断言让TypeScript识别最终的混合类类型。
内容的提问来源于stack exchange,提问作者Vlad Nicula
相关产品推荐
相关产品推荐

