Typescript 从超级调用推断类参数类型

Typescript 从超级调用推断类参数类型,typescript,generics,Typescript,Generics,在我使用的项目中,有一个ClientEvents接口,用于保存事件参数元组类型: interface ClientEvents { ready: []; warn: [reason: string] message: [message: Message]; // ...some more events } 我还有一个EventHandler类,它接受一个类型参数: abstract class EventHandler<E extends keyof ClientEven

在我使用的项目中,有一个
ClientEvents
接口,用于保存事件参数元组类型:

interface ClientEvents {
  ready: [];
  warn: [reason: string]
  message: [message: Message];
  // ...some more events
}
我还有一个
EventHandler
类,它接受一个类型参数:

abstract class EventHandler<E extends keyof ClientEvents> {

  protected constructor(public eventName: E) {}

  abstract execute(...args: ClientEvents[E]): void;
}

有没有一种方法可以使用
super()
调用的参数推断类参数类型?

没有,不容易;推理通常不是这样的。当然,你可以写出来:

class ReadyHandler extends EventHandler<"ready"> {    
  public constructor() {  super('ready');  }    
  public execute() {}
}
不过,我不确定这是否值得


不,不容易;推理通常不是这样的。当然,你可以写出来:

class ReadyHandler extends EventHandler<"ready"> {    
  public constructor() {  super('ready');  }    
  public execute() {}
}
不过,我不确定这是否值得


如果您正在创建一个类的实例,则可以从构造函数参数推断泛型类型,但在子类化的情况下,
super
不会发生这种情况。扩展类时,TypeScript需要泛型类型作为类型定义的一部分。我猜,但我认为这可能是因为TypeScript不一定知道在调用
super
之前是否需要泛型类型(如果调用正确的话)

您还可以通过使子类泛型并将泛型类型传递给超类来解决这个问题

type EventKeys = keyof ClientEvents;

class ReadyHandler<E extends EventKeys> extends EventHandler<E> {
  constructor() {
    // cast is necessary or TS will complain since you could technically
    // do `new ReadyHandler<'wait'>`.
    super('ready' as E);
  }
}
type EventKeys=keyof ClientEvents;
类ReadyHandler扩展了EventHandler{
构造函数(){
//强制转换是必要的,否则TS会投诉,因为您可能会
//做“新的预备手”。
super('ready'作为E);
}
}
在这种情况下,
E
是从
ReadyHandler
的构造函数正确推断出来的,因此您可以调用
newreadyHandler()
,而无需指定类型参数


另一个答案中给出了另一种选择,即仅指定类型,如
EventHandler
中所示,这当然需要您编写两次
'ready'
。你认为什么更方便取决于你。

如果你正在创建一个类的实例,泛型类型可以从构造函数参数中推断出来,但是在子类化的情况下,这不会发生在
super
中。扩展类时,TypeScript需要泛型类型作为类型定义的一部分。我猜,但我认为这可能是因为TypeScript不一定知道在调用
super
之前是否需要泛型类型(如果调用正确的话)

您还可以通过使子类泛型并将泛型类型传递给超类来解决这个问题

type EventKeys = keyof ClientEvents;

class ReadyHandler<E extends EventKeys> extends EventHandler<E> {
  constructor() {
    // cast is necessary or TS will complain since you could technically
    // do `new ReadyHandler<'wait'>`.
    super('ready' as E);
  }
}
type EventKeys=keyof ClientEvents;
类ReadyHandler扩展了EventHandler{
构造函数(){
//强制转换是必要的,否则TS会投诉,因为您可能会
//做“新的预备手”。
super('ready'作为E);
}
}
在这种情况下,
E
是从
ReadyHandler
的构造函数正确推断出来的,因此您可以调用
newreadyHandler()
,而无需指定类型参数


另一个答案中给出了另一种选择,即仅指定类型,如
EventHandler
中所示,这当然需要您编写两次
'ready'
。您认为什么更方便取决于您。

看起来这就是我一直在寻找的解决方案。谢谢看起来这就是我一直在寻找的解决方案。谢谢