node.js - 扩展事件定义 - 接口(interface)错误地实现了接口(interface)

标签 node.js typescript events interface

我正在尝试使用与以下示例中同名的接口(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'>() 创建新发射器时使用此代码, onemit函数将需要带有 'special_event_name' 的事件类型。

关于node.js - 扩展事件定义 - 接口(interface)错误地实现了接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60300587/

相关文章:

node.js - Express静态服务器-设置dir文件夹

typescript - NestJS 在 e2e 测试中模拟 JWT 身份验证

java - 在 Java GUI 中显示鼠标所在位置键入的字符

azure - 用于管理数百万订阅者(即客户)的 Webhook 架构

javascript - 为什么我的nodejs pdf上传代码返回Status 415 "unsupported Media Type"

javascript - 在数据库中的循环 (for) 中插入值时出现问题 : same value is inserted - node js/sql

javascript - JSON 对象属性转换为 JSON 对象名称

javascript - 从 CustomEvent 获取事件的名称

javascript - 按键事件,不希望的 native 行为

javascript - Sails.js如何在不保存数据库的情况下管理数据