![](/img/trans.png)
[英]Typescript: Get correct member type from super call argument in derived 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) {
}
}
不过,我不确定这是否值得。
如果您正在创建 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.