Node.js 扩展事件定义-接口未正确实现接口

Node.js 扩展事件定义-接口未正确实现接口,node.js,typescript,events,interface,Node.js,Typescript,Events,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 {}

我尝试在代码中使用与以下示例中相同名称的接口和类强制执行事件定义:

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完成和确保事件对象仅广播这些事件而言,这本身工作得很好

当我尝试扩展此接口时出现问题,如下所示:

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:接口“SpecificClientEvents”错误地扩展了接口“ClientEvents”。
用于接口

TS2415:类“SpecificClientEvents”错误地扩展了基类“ClientEvents”。

我还尝试按照以下示例将类和接口分离为单独的定义:

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不会像类和接口具有相同名称时那样检测事件名称。这可能是IDE的问题吗?这不适用于父类和子类

我还能够执行
newspecificclients().emit(“未定义的事件”)没有任何错误

编辑:

如果我手动将父接口中的方法添加到子接口中,则效果绝对不错。但是如果我需要手动添加方法,那么首先扩展父级有什么意义呢

编辑2:

为了满足我的需要,我选择将与以下代码一起使用

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;
}
export-type clienteventmitter=stricteventmitter;
导出接口客户端{
事件名称:(数据:字符串)=>void;
}
导出类型指定的客户验证提交人=严格验证提交人;
导出接口特定客户端扩展客户端{
子事件名称:(数据:字符串)=>void;
}

我想您可能没有意识到您正在使用一个名为的功能,这意味着您的两个接口具有不兼容的类型,并且您的第一个示例具有预期的行为

为清晰起见,以下是一个简化版本:

interface A {
  prop: 'String literal type';
}

interface B extends A {
  prop: 'Another string literal type';
}
这将给您一条错误消息,说明:
Type''other string literal Type'不可分配给Type''string literal Type'

我还能够执行新的SpecificClientEvents().emit(“事件”) 这没有定义“);使用第二个示例时没有任何错误

这似乎是因为
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);
  }
}
导出类客户端事件扩展EventEmitter{
on(事件:T,数据:(数据:字符串)=>void):此{
返回super.on(事件、数据);
}
发出(事件:T,数据:字符串):布尔值{
返回super.emit(事件、数据);
}
}
使用此代码,当您使用
new ClientEvents()
创建一个新的发射器时,
上的
emit
函数将需要具有
'special\u event\u name'
类型的事件。

答案是满足您确切需要的最佳答案,但如果您需要事件名称与其数据类型之间更复杂的映射,你可以用这样的东西

export interface ClientEvents<T> {
    on(event: keyof T, data: (d: T[typeof event]) => void) : this;
    emit(event: keyof T, data: T[typeof event]) : boolean;
}

type SpecificEvents = {
    eventName1: string,
    eventName2: number
}

class SpecificClientEvents implements ClientEvents<SpecificEvents> {
    on(event: keyof SpecificEvents, data: (d: SpecificEvents[typeof event]) => void) : this {
        switch (event) {
            case "eventName1":
                // compiler forces you to pass string
                data("string value");
                break;
            case "eventName2":
                // compiler forces you to pass number
                data(2);
                break;
            default:
                break;
        }

        return this;
    }

    emit(event: keyof SpecificEvents, data: SpecificEvents[typeof event]): boolean {
        switch (event) {
            case "eventName1":
                // data is of type string
                break;
            case "eventName2":
                // data is of type number
                break;
            default:
                break;
        }

        return true;
    }
}
导出接口客户端事件{
on(event:keyof T,data:(d:T[typeof event])=>void):这个;
emit(event:keyof T,data:T[typeof event]):布尔值;
}
类型特定事件={
eventName1:string,
事件名称2:编号
}
类SpecificClientEvents实现ClientEvents{
on(event:keyof SpecificEvents,data:(d:SpecificEvents[typeof event])=>void):此{
开关(事件){
案例“eventName1”:
//编译器强制您传递字符串
数据(“字符串值”);
打破
案例“eventName2”:
//编译器强制您传递数字
数据(2);
打破
违约:
打破
}
归还这个;
}
发出(事件:keyof SpecificEvents,数据:SpecificEvents[typeof event]):布尔值{
开关(事件){
案例“eventName1”:
//数据类型为字符串
打破
案例“eventName2”:
//数据类型为数字
打破
违约:
打破
}
返回true;
}
}
或者更简单的内联类型,其中大多数IDE将自动完成实现并更正参数类型

class SimpleEvents implements ClientEvents<{ eventName: number }> {
    on(event: "eventName", data: (d: number) => void): this {
        throw new Error("Method not implemented.");
    }

    emit(event: "eventName", data: number): boolean {
        throw new Error("Method not implemented.");
    }
}
类SimpleEvents实现客户端事件{
on(事件:“eventName”,数据:(d:number)=>void):此{
抛出新错误(“方法未实现”);
}
发出(事件:“eventName”,数据:编号):布尔值{
抛出新错误(“方法未实现”);
}
}
这里是链接到