在 TypeScript 中使用类型变量从抽象 class 为派生的 classes 分配泛型

Assigning a generic type for derived classes from an abstract class with type variables in TypeScript

我有一个抽象 class Base 接受要在 class 中使用的类型变量 <T>。然后我有很多派生的 classes 明确定义了类型,比如 class Derived extends Base<string> {...}

我想要一个变量(或变量数组),其类型可以是任何派生的 classes,无论 <T> 是什么。然后我希望能够使用该变量来创建这些 Derived classes.

的新实例

这是我尝试过的一些代码。从那里,我迷路了。

TypeScript Playground link

abstract class Base<T> {
    abstract value: T;
}

class Derived extends Base<string> {
    value = 'Hello world!';
}

class SecondDerived extends Base<number> {
    value = 1234;
}

// This has type (typeof Derived | typeof SecondDerived)
let classes_A = [Derived, SecondDerived];

// This obviously works too, but with many derived classes can get long and tedious
let classes_B: (typeof Derived | typeof SecondDerived)[] = [];
classes_B.push(Derived);
classes_B.push(SecondDerived);

// This does NOT work
let classes_C: Base<any>[] = [];
classes_C.push(Derived); // "typeof Derived is not assignable to type Base<any>"

// This does NOT work
let classes_D: Base<unknown>[] = [];
classes_D.push(Derived); // "typeof Derived is not assignable to type Base<unknown>"

// This does NOT work
let classes_E: Base<string>[] = [];
classes_E.push(Derived); // "typeof Derived is not assignable to type Base<string>"

// This does NOT work
let classes_F: (typeof Base)[] = [];
classes_F.push(Derived); // "typeof Derived is not assignable to typeof Base"

您需要为构造函数定义类型:

type CtorBase = new () => Base<any>;

现在您可以使用它来保存 Base 的构造函数列表:

let classes_C: CtorBase [] = [];
classes_C.push(Derived);

我的建议是:

let classes: Array<new (...args: any) => Base<any>> = [];
classes.push(Derived); // okay
classes.push(SecondDerived); // okay

数组的元素类型应该是"a constructor of any subtype of Base<T> for any T"。要说 "a constructor of X" 作为类型,您可以使用 anyany[] 类型的 newable signature, like new () => X. Note that the signature specifies what types and number arguments the constructor expects; if you don't care, then you can use a rest argument,例如 new (...args: any) => X.

由于您正在构建的类型是任何 TBase<T> 的任何子类型,并且您可能不需要跟踪哪个,那么 Base<any> 可能是好的足够。 (如果不是,那么请详细说明它不起作用的用例)。

好的,希望对您有所帮助;祝你好运!

Playground link to code