Typescript 键入从同一基类继承的类列表的正确方法是什么?

Typescript 键入从同一基类继承的类列表的正确方法是什么?,typescript,class,types,Typescript,Class,Types,在TypeScript中,我试图正确键入“从基类继承的类数组”类型的变量 使用这段代码,我得到错误“无法创建抽象类的实例。ts(2511),我理解。但我不想实例化Base的一个成员,只想实例化它的后代 abstract class Base { abstract execute(param: string): void; protected name: string; constructor(name: string) { this.name = name; }

在TypeScript中,我试图正确键入“从基类继承的类数组”类型的变量

使用这段代码,我得到错误“无法创建抽象类的实例。ts(2511),我理解。但我不想实例化Base的一个成员,只想实例化它的后代

abstract class Base {
  abstract execute(param: string): void;
  protected name: string;

  constructor(name: string) {
    this.name = name;
  }

  public commonMethod() {
    console.log("Common Method");
  }
}

class A extends Base {
  execute() {
    console.log(`Hello from A, ${this.name}`);
    this.commonMethod();
  }
}

class B extends Base {
  execute() {
    console.log(`Hello from B, no-name`);
  }
}

const list: typeof Base[] = [A, B];

const names = ["Phil", "Andy", "Bob"];

names.map((name) => list.map((cl) => new cl(name)));
如何正确键入
const list:???[]=[A,B]

当我切换到
const list:typeof A[]=[A,B]
时,它会工作,但随后会提示所有列表项都是
A
,而不是


问题是错误是正确的。
list
的类型是
typeof Base[]
,并且不能实例化
Base
。据我所知,无法将
list
声明为“从
Base
派生的非抽象构造函数数组”:

因此,尽管我不喜欢它,但我认为最好的办法是让TypeScript相信
Base
不是抽象的,并通过在
Base
构造函数中不允许直接构造,将其直接实例化为运行时错误,而不是编译时错误:

类基{
// ...
构造函数(名称:string){
if(new.target==Base){
抛出新错误(“不能直接实例化基”);
}
this.name=名称;
}
// ...
}
下面是一个完整的示例():

类基{
受保护名称:字符串;
构造函数(名称:string){
if(new.target==Base){
抛出新错误(“不能直接实例化基”);
}
this.name=名称;
}
execute():void{
}
公共方法(){
console.log(“通用方法”);
}
}
A类扩展基础{
执行(){
log(`Hello from A,${this.name}`);
此方法为.commonMethod();
}
}
B类扩展了基本类{
执行(){
log(`Hello from B,no name`);
}
}
常数列表:基本类型[]=[A,B];
常量名称=[“菲尔”、“安迪”、“鲍勃”];
//这很有效
const instances=names.map((name)=>list.map((cl)=>newcl(name));
控制台日志(“A”);
新A(“A”);//这也一样
控制台日志(“B”);
新B(“B”);//还有这个
控制台日志(“C”);
新基地(“c”);//但直接实例化Base会引发运行时错误

您可以使用构造函数签名而不是类本身:


const list: Array<new (name: string) => Base> = [A, B];

const names = ["Phil", "Andy", "Bob"];

names.map((name) => list.map((cl) => new cl(name)));

常数列表:数组基>=[A,B];
常量名称=[“菲尔”、“安迪”、“鲍勃”];
names.map((name)=>list.map((cl)=>newcl(name));

这将不允许您访问静态,如果您需要还可以使用的静态:

const list: Array<Omit<typeof Base, never> & (new (name: string) => Base)> = [A, B];

const names = ["Phil", "Andy", "Bob"];

names.map((name) => list.map((cl) => new cl(name)));
list[0].foo();
常数列表:数组基)>=[A,B];
常量名称=[“菲尔”、“安迪”、“鲍勃”];
names.map((name)=>list.map((cl)=>newcl(name));
列表[0]。foo();

旁注:不要仅使用
map
循环数组。如果您没有使用它返回的数组(因为您没有在
名称.map(…)
末尾),只需使用
for of
循环,或
forEach
,或。这非常有趣。我只能想到黑客,而不是解决方案。嗨@T.J.Crowder谢谢你的留言!在编写示例代码nice时忘记了这一点!!……-)