我正在尝试使用与以下示例中同名的接口(interface)和类在我的代码中强制执行事件定义:
export declare interface ClientEvents {
on(event: "event_name", data: (data: string) => void) : this;
emit(event: "event_name", data: string) : boolean;
}
export class ClientEvents extends EventEmitter {}
这对于 IDE 完成本身很有效,并确保只有这些事件由事件对象广播。
当我尝试扩展这个接口(interface)时,问题就来了,如下:
export declare interface SpecificClientEvents extends ClientEvents {
on(event: "child_event_name", data: (data: string) => void) : this;
emit(event: "child_event_name", data: string) : boolean;
}
export class SpecificClientEvents extends ClientEvents {}
我收到以下错误:
TS2430:接口(interface)“SpecificClientEvents”错误地扩展了接口(interface)“ClientEvents”。
用于接口(interface)
TS2415:类 'SpecificClientEvents' 错误地扩展了基类 'ClientEvents'。
用于类
我还尝试按照以下示例将类和接口(interface)分成单独的定义:
export interface ClientEventDefinitions {
on(event: "event_name", data: (data: string) => void) : this;
emit(event: "event_name", data: string) : boolean;
}
export class ClientEvents extends EventEmitter implements ClientEventDefinitions {}
export interface SpecificClientEventDefinitions {
on(event: "child_event_name", data: (data: string) => void) : this;
emit(event: "child_event_name", data: string) : boolean;
}
export class SpecificClientEvents extends ClientEvents implements SpecificClientEventDefinitions {}
这编译正常,但我的 IDE 没有像类和接口(interface)具有相同名称时那样检测事件名称。这可能是IDE的问题吗?这不适用于父类和子类。
我还能够使用第二个示例执行 new SpecificClientEvents().emit("an event that is not defined");
而不会出现任何错误。
编辑:
如果我手动将父接口(interface)中的方法添加到子接口(interface),这绝对可以正常工作。但是,如果我需要手动添加方法,那么首先扩展父级有什么意义呢?
编辑 2:
我选择使用 strict event emitter package用下面的代码来满足我的需求
export type ClientEventEmitter = StrictEventEmitter<EventEmitter, ClientEvents>;
export interface ClientEvents {
event_name: (data: string) => void;
}
export type SpecificClientEventsEmitter = StrictEventEmitter<EventEmitter, SpecificClientEvents>;
export interface SpecificClientEvents extends ClientEvents {
child_event_name: (data: string) => void;
}
最佳答案
我想您可能没有意识到您正在使用一个名为 string literal types 的功能,这意味着您的两个接口(interface)具有不兼容的类型,并且您的第一个示例具有预期的行为。
为清楚起见,这里有一个简化版本:
interface A {
prop: 'String literal type';
}
interface B extends A {
prop: 'Another string literal type';
}
这会给您一条错误消息:Type '"Another string literal type"' is not assignable to type '"String literal type"'
I'm also able to execute new SpecificClientEvents().emit("an event that isn't defined"); without any errors using the 2nd example.
这似乎是因为 implements
不强制使用 SpecificClientEventDefinitions
中的字符串文字类型和 SpecificClientEvents
类改为使用 EventEmitter
中的类型(string | symbol
)。
这是一种使用泛型类的替代方法,我认为它可以解决您的问题:
export class ClientEvents<T extends string> extends EventEmitter {
on(event: T, data: (data: string) => void): this {
return super.on(event, data);
}
emit(event: T, data: string): boolean {
return super.emit(event, data);
}
}
当您使用 new ClientEvents<'special_event_name'>()
创建新发射器时使用此代码, on
和 emit
函数将需要带有 'special_event_name'
的事件类型。
关于node.js - 扩展事件定义 - 接口(interface)错误地实现了接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60300587/