在扩展 EventEmitter 的 TypeScript 类中声明事件

Posted

技术标签:

【中文标题】在扩展 EventEmitter 的 TypeScript 类中声明事件【英文标题】:Declaring events in a TypeScript class which extends EventEmitter 【发布时间】:2017-01-01 17:49:44 【问题描述】:

我有一个扩展EventEmitter 的类,它可以发出事件hello。如何使用特定的事件名称和侦听器签名声明 on 方法?

class MyClass extends events.EventEmitter 

  emitHello(name: string): void 
    this.emit('hello', name);
  

  // compile error on below line
  on(event: 'hello', listener: (name: string) => void): this;

【问题讨论】:

错误是什么?并且您的 on 方法似乎缺少主体。 正如@NitzanTomer 所说,您的on 方法缺少主体,或者您想将event 参数声明为'hello' 以外的其他类型。 This answer 应该可以帮到你。 【参考方案1】:

最有用的方法是使用declare

declare interface MyClass 
    on(event: 'hello', listener: (name: string) => void): this;
    on(event: string, listener: Function): this;


class MyClass extends events.EventEmitter 
    emitHello(name: string): void 
        this.emit('hello', name);
    

请注意,如果您要导出您的类,接口和类都必须使用export 关键字声明。

【讨论】:

只需让 Update 1 成为答案,因为另一种方式更成问题。【参考方案2】:

这是我能够弄清楚的。用泛型覆盖默认函数!

interface IEmissions 
  connect: () => void
  test: (property: string) => void


class MyClass extends events.EventEmitter 
  private _untypedOn = this.on
  private _untypedEmit = this.emit
  public on = <K extends keyof IEmissions>(event: K, listener: IEmissions[K]): this => this._untypedOn(event, listener)
  public emit = <K extends keyof IEmissions>(event: K, ...args: Parameters<IEmissions[K]>): boolean => this._untypedEmit(event, ...args)

  this.emit('test', 'Testing') // This will be typed for you!


// Example:
const inst = new MyClass()
inst.on('test', info => console.log(info)) // This will be typed!

【讨论】:

这正是我所需要的。这提供了在仍然强制输入的同时覆盖函数的能力。 非常优雅!我什至通过简单地调用super 不必将原始方法存储为成员来简化这一点。这在 TS 4.1.3 中对我有用:public on&lt;K extends keyof MyEvents&gt;(e: K, listener: MyEvents[K]): this return super.on(e, listener); 【参考方案3】:

您可以为此使用typed event emitter package。

例如:

import  EventEmitter  from 'tsee';

const events = new EventEmitter<
    foo: (a: number, b: string) => void,
>();

// foo's arguments is fully type checked
events.emit('foo', 123, 'hello world');

这个包还提供接口和一些实用程序。

【讨论】:

这太棒了,我喜欢你的包!【参考方案4】:

为了扩展@SergeyK 的答案,您可以在不重复事件类型的情况下对emiton 函数进行类型检查和完成。

    为每种事件类型定义事件侦听器签名:
interface MyClassEvents 
  'add': (el: string, wasNew: boolean) => void;
  'delete': (changedCount: number) => void;

    根据 EventListeners (MyClassEvents) 函数签名声明构造 MyClass 类型的接口:
declare interface MyClass 
  on<U extends keyof MyClassEvents>(
    event: U, listener: MyClassEvents[U]
  ): this;

  emit<U extends keyof MyClassEvents>(
    event: U, ...args: Parameters<MyClassEvents[U]>
  ): boolean;

    只需定义扩展EventEmitter的类:
class MyClass extends EventEmitter 
  constructor() 
    super();
  


现在您将对onemit 函数进行类型检查:

不幸的是,您只能对这两个函数进行补全和类型检查(除非您在 MyClass 接口中定义了更多函数)。

要获得更通用的解决方案,您可以使用this package。 注意:它不会增加运行时开销。

import  TypedEmitter  from 'tiny-typed-emitter';

interface MyClassEvents 
  'add': (el: string, wasNew: boolean) => void;
  'delete': (changedCount: number) => void;


class MyClass extends TypedEmitter<MyClassEvents> 
  constructor() 
    super();
  

【讨论】:

那个包真是太棒了。 到目前为止迄今为止我见过的最用户友好的解决方案。谢谢! @MaxTruxa 很高兴你发现它很有用:)【参考方案5】:

将the official typing package 用于events library:

npm install events @types/events

【讨论】:

这是一个不同的包

以上是关于在扩展 EventEmitter 的 TypeScript 类中声明事件的主要内容,如果未能解决你的问题,请参考以下文章

node node是什么 Buffer 模块化开发 第三方模块 事件订阅机制EventEmitter

如何在现有对象上调用EventEmitter

有啥方法可以在 Angular2 中测试 EventEmitter?

Nodejs - EventEmitter,Buffer

EventEmitter

EventEmitter 的正确用途是啥?