简体   繁体   English

有没有办法在TypeScript中组合类mixin?

[英]Is there a way to compose class mixins in TypeScript?

I have a hierarchy of class mixins that work in plain JavaScript. 我有一个类mixin的层次结构,可以在纯JavaScript中工作。

const
  AsFoo = ( superclass ) => class extends superclass {
    get foo(){ return true; }
  },

  AsFooBar = ( superclass ) => class extends AsFoo( superclass ){
    get bar(){ return true; }
  },

  FooBar = AsFooBar( Object ),
  fb = new FooBar();

console.log( fb.foo, fb.bar );
// true, true

However when I translate them to TypeScript, I get an error with AsFoo( superclass ) . 但是,当我将它们转换为TypeScript时,我收到了AsFoo( superclass )的错误。

type Constructor<T = {}> = new ( ...args: any[] ) => T;

interface Foo {
    foo: boolean;
}

interface FooBar extends Foo {
    bar: boolean;
}

const
  AsFoo = <T extends Constructor>( superclass: T ): Constructor<Foo> & T => class extends superclass implements Foo {
    get foo(){ return true; }
  },
  AsFooBar = <T extends Constructor>( superclass: T ): Constructor<FooBar> & T => class extends AsFoo<T>( superclass ) implements FooBar {
    get bar(){ return true; }
  };

// Type 'Constructor<Foo> & T' is not a constructor function type. ts(2507)

Is there something I can do to make TypeScript work with this pattern? 我可以做些什么来使TypeScript使用这种模式吗? I'd rather not just // @ts-ignore: ¯\\_(ツ)_/¯ it. 我宁愿不只是// @ts-ignore: ¯\\_(ツ)_/¯它。

I am currently using TypeScript 3.2.4. 我目前正在使用TypeScript 3.2.4。

export type Constructor<T = {}> = new (...args: any[]) => T;
/* turns A | B | C into A & B & C */
export type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void)
    ? I
    : never;
/* merges constructor types - self explanitory */
export type MergeConstructorTypes<T extends Array<Constructor<any>>> = UnionToIntersection<InstanceType<T[number]>>;

export function Mixin<T extends Array<Constructor<any>>>(constructors: T): Constructor<MergeConstructorTypes<T>> {
    const cls = class {
        state = {};

        constructor() {
            constructors.forEach((c: any) => {
                const oldState = this.state;
                c.apply(this);
                this.state = Object.assign({}, this.state, oldState);
            });
        }
    };
    constructors.forEach((c: any) => {
        Object.assign(cls.prototype, c.prototype);
    });
    return cls as any;
}

this is an implementation i was playing around with awhile back, it also merges the states of each class but feel free to alter that part to suit your needs. 这是我正在玩一段时间的实现,它还合并了每个类的状态,但随意改变那部分以满足您的需求。

The usage is as follows... 用法如下......

class A {
    getName() {
        return "hello"
    }
}


class B {
    getClassBName() {
        return "class B name"
    }
}

class CombineAB extends Mixin([A, B]) {
    testMethod() {
        this.getClassBName //is here
        this.getName // is here
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM