在 TypeScript 中为具有类型变量的抽象类中的派生类分配泛型类型

Posted

技术标签:

【中文标题】在 TypeScript 中为具有类型变量的抽象类中的派生类分配泛型类型【英文标题】:Assigning a generic type for derived classes from an abstract class with type variables in TypeScript 【发布时间】:2020-05-22 23:02:35 【问题描述】:

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

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

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

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"

【问题讨论】:

【参考方案1】:

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

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

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

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

【讨论】:

大概是classes_X 持有constructors而不是instances,对吧? 感谢您的回复,但不幸的是它并没有解决这个问题。我实际上确实想将类类型放在这些数组中,而不是类的实例中。所以我确实打算做classes_C.push(Derived) @jcalz 是的,我想持有构造函数,而不是类的实例 好的,更改了我的编辑。第一次没听懂,抱歉:) 这也解决了。我也喜欢这样,因为我可以根据所需的参数定义多种类型,然后使用所有这些。谢谢!【参考方案2】:

我的建议是这样的:

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

数组的元素类型应该是“任何Base&lt;T&gt; 的任何T 子类型的构造函数”。要说“X 的构造函数”作为类型,您可以使用newable signature,如new () =&gt; X。请注意,签名指定构造函数期望的类型和数量参数;如果你不关心,那么你可以使用anyany[] 类型的rest argument,比如new (...args: any) =&gt; X

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

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

Playground link to code

【讨论】:

这解决了!我也有需要强制执行的参数,但它们对于每个派生类都是相同的,所以这是完美的。谢谢!

以上是关于在 TypeScript 中为具有类型变量的抽象类中的派生类分配泛型类型的主要内容,如果未能解决你的问题,请参考以下文章

TypeScript中的接口和抽象类

TypeScript(15): 接口

如何在抽象父类中为实现打字稿制作泛型方法?

如何在具有多个子项目的 Visual Studio 中为 C# 解决方案设置通用值(抽象)?

第三节:TypeScript对象类型

typescript中abstractClass(抽象类)extendsabstract