繁体   English   中英

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

[英]Infer class argument type from super call

在我使用discord.js的项目中,有一个ClientEvents接口包含事件参数元组类型:

interface ClientEvents {
  ready: [];
  warn: [reason: string]
  message: [message: Message];
  // ...some more events
}

我还有一个EventHandler class,它接受一个类型参数:

abstract class EventHandler<E extends keyof ClientEvents> {

  protected constructor(public eventName: E) {}

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

问题是我不能使用E的类型推断来扩展这个 class ,即使它是在super()调用中明确设置的:

// Error: Generic type 'EventHandler<E>' requires 1 type argument(s).
class ReadyHandler extends EventHandler {

  public constructor() {
    super('ready'); // I want to infer the type using this argument
  }

  public execute() {
    // Some more code
  }
}

有没有办法使用super()调用的 arguments 来推断 class 参数类型?

不,不容易; 推理通常不会那样工作。 你当然可以写出来:

class ReadyHandler extends EventHandler<"ready"> {    
  public constructor() {  super('ready');  }    
  public execute() {}
}

如果您想避免这种冗余,您可以重构或封装EventHandler以便给它一个E类型的实际字符串,并从中推断出E 生成的 class 将不再是通用的。 例如:

function SpecificHandler<E extends keyof ClientEvents>(eventName: E) {
  abstract class SpecificHandler extends EventHandler<E> {
    constructor() { super(eventName) };
  }
  return SpecificHandler;
}

class MessageHandler extends SpecificHandler("message") {
  public execute(msg: Message) {

  }
}

不过,我不确定这是否值得。

Playground 代码链接

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

您还可以通过使子类泛型并将泛型类型传递给超级 class 来解决此问题。

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);
  }
}

在这种情况下, E是从ReadyHandler的构造函数中正确推断出来的,因此您可以在不指定类型参数的情况下调用new ReadyHandler()

另一个答案中提供了另一种选择,它只是将类型指定为EventHandler<'ready'> ,这当然需要你写两次'ready' 由您决定您认为更方便的方式。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM