带有可选超类的Typescript mixin函数

时间:2019-03-12 12:28:45

标签: typescript mixins typing

我正在尝试构建一个可选需要一个超类的mixin函数。这样做的理由是,我们通常只是建立中间类以从我们的mixins开始。我对以下声明很有信心,但是它们不起作用:

interface Test {
  readonly __TEST: "test";
  new (...args: any[]): {
    readonly test: "test";
  };
}

function TestMixin<SuperClass extends new (...args: any[]) => any>(
  superClass?: SuperClass
) {
  const defaultClass = class {};
  /* Error: Type 'new (...args: any[]) => any' is not assignable to type 'SuperClass extends undefined ? typeof defaultClass : undefined'.ts(2322) */
  const sc: typeof superClass extends undefined ? typeof defaultClass : undefined = superClass === undefined ? defaultClass : superClass;

  /* Error: Type 'SuperClass extends undefined ? typeof defaultClass : undefined' is not a constructor function type. */
  class T extends sc implements InstanceType<Test> {
    public static readonly __TEST = "test";
    public readonly test = "test";
  }

  return T;
}

2 个答案:

答案 0 :(得分:1)

您不能扩展条件类型,Typescripts希望extends子句中的子句是构造函数,而不是其他任何更复杂的类型。

我认为在这种情况下,最简单的解决方案是使用类型断言来欺骗编译器:

interface Test {
    readonly __TEST: "test";
    new(...args: any[]): {
        readonly test: "test";
    };
}

function TestMixin<SuperClass extends new (...args: any[]) => any = new () => {}>(
    superClass?: SuperClass
) {
    const defaultClass = class { };
    /* ok */
    const sc = (superClass === undefined ? defaultClass : superClass) as SuperClass;

    /* Ok now */
    class T extends sc implements InstanceType<Test> {
        public static readonly __TEST = "test";
        public readonly test = "test";
    }

    return T;
}

let a = TestMixin();
new a().test;

let b = TestMixin(class {
    constructor(n: number) { console.log("Hi") }
    m() { }
});
new b(1).test;
new b(1).m();

只要没有人为TestMixin指定显式类型参数并省略该参数,它就可以正常工作。

答案 1 :(得分:0)

找到一个共同的分母-Constructor类型。

interface Constructor<T = any> {
  new (...args: any[]): T;
}
interface Test {
    readonly __TEST: "test";
    new(...args: any[]): {
        readonly test: "test";
    };
}

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

function TestMixin<SuperClass extends new (...args: any[]) => any>(
    superClass?: SuperClass
) {
    const defaultClass: Constructor = superClass || class { };

    return class T extends defaultClass implements InstanceType<Test> {
        public static readonly __TEST = "test";
        public readonly test = "test";
    }
}