Typescript多继承并提示, 问一下大佬们,怎样通过加一个类型解析提示静态类型


type Constructor<T = Record<string, any>> = new (...args: any[]) => T;

type UnionToIntersection<U> = (U extends any ? (k: U) => any : never) extends (k: infer I) => any ? I : never;

// type UnionToIntersection2<U> = U extends any ? (k: U) => any : never

function Mixin<T extends Constructor[]>(...mixins: T): Constructor<UnionToIntersection<InstanceType<T[number]>>>;

// function Mixin<T extends Constructor[]>(...mixins: T): Constructor<UnionToIntersection2<T[number]>>;

function Mixin<T extends Constructor[]>(...mixins: T) {

    class Mix { }

    const mergeDesc = {};

    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 Base {

    static printBase() {

        console.warn(`class<Base>`)

    }

    same() {

        console.log('base same')

    }

    baseFunc() {

        console.log('base func')

    }

}

class A {

    static printA() {

        console.warn(`class<A>`)

    }

    same() {

        console.log('a same')

    }

    aFunc() {

        console.log('a func')

    }

}

class B {

    static printB() {

        console.warn(`class<B>`)

    }

    same() {

        console.log('b same')

    }

    bFunc() {

        console.log('b func')

    }

}

class MixClass extends Mixin(Base, A, B) {

    constructor() {

        super();

    }

    static print() {

        this.printBase() // 报红,不能提示静态类型

        this.printA() // 报红,不能提示静态类型

        this.printB() // 报红,不能提示静态类型

    }

    call() {

        this.same();

        this.baseFunc();

        this.aFunc();

        this.bFunc();

    }

}

MixClass.print();

new MixClass().call();

这个 API 看起来和 Vue2 那套 Class Component 装饰器很像,可以看看它们的类型是怎么实现的?可能他们也没有处理好这个问题,或者没法处理。

https://github.com/vuejs/vue-class-component
https://github.com/facing-dev/vue-facing-decorator

组合优于继承。Vue 新的那套 Composition API ,在类型友好这一点上比 mixin 强太多了。

1赞