TypeScript创造的联合类型(Mixin)中,如何支持 prototype链判断?如何让 isInherit(C, A) 和 isInherit(C, B) 判定同时成立?

TypeScript Mixin 创造的联合类型中,如何支持 prototype 链支持?

type Constructor<T = Record<string, any>> = new (...args: any[]) => T;
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
function Mixin<T extends Constructor[]>(...mixins: T): Constructor<UnionToIntersection<InstanceType<T[number]>>> & UnionToIntersection<T[number]>;

function Mixin<T extends Constructor[]>(...mixins: T) {
    class Mix { }
    const mergeDesc: any = {};

    function copyProperties(target: any, source: any) {
        for (let key of Reflect.ownKeys(source)) {
            if (key !== 'constructor' && key !== 'prototype' && key !== 'name') {
                let desc = Object.getOwnPropertyDescriptor(source, key);
                if (desc) {
                    mergeDesc[key] = mergeDesc[key] || [];
                    mergeDesc[key].push(desc.value);
                    Object.defineProperty(target, key, desc);
                }
            }
        }
    }

    for (let mixin of mixins) {
        copyProperties(Mix, mixin); // 拷贝静态属性
        copyProperties(Mix.prototype, mixin.prototype); // 拷贝原型属性
    }

    for (const key in mergeDesc) {
        const fns = mergeDesc[key];
        Object.defineProperty(Mix.prototype, key, {
            configurable: true,
            enumerable: true,
            writable: true,
            value(...args: any[]) {
                const context = this;
                fns.forEach(function (fn: Function) {
                    fn.call(context, ...args);
                });
            },
        });
    }
    return Mix
}



class A {
    printA() {
        console.log("A");
    }
}

class B {
    printB(sss: string) {
        console.log("B");
    }
}

class C extends Mixin(A, B) {
    constructor() {
        super();
    }

    printC() {
        this.printA();
        this.printB('');
    }
}

function isInherit(childClass: any, parentClass: any): boolean {
    let child = childClass;
    while (child) {
        if (child === parentClass) {
            return true;
        }
        child = child.__proto__;
    }
    return false;
}

if (isInherit(C, A)) { // 判定不成立
    console.log('C inherit A');
} else {
    console.log('C not inherit A');
}

if (isInherit(C, B)) { // 判定不成立
    console.log('C inherit B');
} else {
    console.log('C not inherit B');
}
阅读 640
1 个回答
type Constructor<T = Record<string, any>> = new (...args: any[]) => T;
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;

function Mixin<T extends Constructor[]>(...mixins: T): Constructor<UnionToIntersection<InstanceType<T[number]>>> & UnionToIntersection<T[number]> {
    class Mix {
        static mixinClasses = mixins;
    }

    const mergeDesc: any = {};

    function copyProperties(target: any, source: any) {
        for (let key of Reflect.ownKeys(source)) {
            if (key !== 'constructor' && key !== 'prototype' && key !== 'name') {
                let desc = Object.getOwnPropertyDescriptor(source, key);
                if (desc) {
                    mergeDesc[key] = mergeDesc[key] || [];
                    mergeDesc[key].push(desc.value);
                    Object.defineProperty(target, key, desc);
                }
            }
        }
    }

    for (let mixin of mixins) {
        copyProperties(Mix, mixin); // 拷贝静态属性
        copyProperties(Mix.prototype, mixin.prototype); // 拷贝原型属性
        // 添加标识属性
        Mix.prototype[`__is${mixin.name}`] = true;
    }

    for (const key in mergeDesc) {
        const fns = mergeDesc[key];
        Object.defineProperty(Mix.prototype, key, {
            configurable: true,
            enumerable: true,
            writable: true,
            value(...args: any[]) {
                const context = this;
                fns.forEach(function (fn: Function) {
                    fn.call(context, ...args);
                });
            },
        });
    }
    return Mix as Constructor<UnionToIntersection<InstanceType<T[number]>>> & UnionToIntersection<T[number]>;
}

class A {
    printA() {
        console.log("A");
    }
}

class B {
    printB(sss: string) {
        console.log("B");
    }
}

class C extends Mixin(A, B) {
    constructor() {
        super();
    }

    printC() {
        this.printA();
        this.printB('');
    }
}

function isInherit(childClass: any, parentClass: any): boolean {
    const parentName = parentClass.name;
    return childClass.prototype[`__is${parentName}`] === true;
}

if (isInherit(C, A)) { // 判定成立
    console.log('C inherit A');
} else {
    console.log('C not inherit A');
}

if (isInherit(C, B)) { // 判定成立
    console.log('C inherit B');
} else {
    console.log('C not inherit B');
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Microsoft
子站问答
访问
宣传栏