子类构造函数的泛型类型

时间:2018-09-16 12:53:21

标签: typescript generics inheritance

我正在寻找一种以通用方式从以下代码中表达[B, C]类型的方法。如果我将鼠标悬停在当前的types位置,我会得到const types: (typeof B | typeof C)[],这有点冗长,添加新项可能会很长。

abstract class A {
    static staticF<T extends A>(this: new () => T): string {
        return 'A'
    }
}

class B extends A {
    static bProp = 1
}
class C extends A {
    static cProp = 1
    static staticF<T extends A>(this: new () => T): string {
        return 'B'
    }
}

const types = [B, C]
types
    .map(t => t.staticF())
    .forEach(x => console.log(x))

我尝试使用const types: typeof A[],但出现以下错误:

  

类型'typeof A'的'this'上下文不能分配给类型'new()=> A'的方法'this'。   无法将抽象构造函数类型分配给非抽象构造函数类型。

我也尝试过const types: typeof extends A[],但TS认为我喝醉了。

如何从共享同一父级的类中表达多个类构造函数的类型?

此外,typeof Anew () => A{new (): A}有什么区别?

1 个答案:

答案 0 :(得分:1)

最简单的答案是typeof Anew () => A{new (): A}之间的区别是什么。最后两个是等效的,{ new() : A }语法是new () => A的更详细的表亲。使用更详细的版本的原因是因为它允许您为构造函数指定更多重载,并且还允许您指定额外的成员(即静态方法)。 typeof A是类A,其中包含构造函数签名以及任何静态变量。如果您只关心能够创建类的实例,那么简单的构造函数签名就足够了。如果还需要访问静态变量,则需要typeof Class

对于您的其他问题,问题在于打字稿将抽象类的构造函数视为第二类构造函数的一部分。除了在派生类内部之外,它不是构造函数,由于不应实例化该类,因此这不是一个坏主意。但是,在这种情况下,这意味着在static上调用A时,类A将无法满足其具有可调用构造函数(this: new () => T)的约束

我发现最简单的解决方案是创建一个扩展typeof A的接口。实际上,这将消除构造函数的抽象性,并允许您创建所需的数组:

type AClass = (typeof A);
interface DerivedAClass extends AClass {}

let types : DerivedAClass[] = [B, C];
types
    .map(t => t.staticF()) // T of staticF will be DerivedAClass
    .forEach(x => console.log(x))

Playground link