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

Node.js 在扩展EventEmitter的TypeScript类中声明事件,node.js,typescript,Node.js,Typescript,我有一个扩展了EventEmitter的类,它可以发出eventhello。如何使用特定的事件名称和侦听器签名在方法上声明 class MyClass extends events.EventEmitter { emitHello(name: string): void { this.emit('hello', name); } // compile error on below line on(event: 'hello', listener: (name: str

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

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;
}

最有用的方法是使用
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
关键字声明。

以下是我能够理解的。用泛型覆盖默认函数

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!
接口{
连接:()=>void
测试:(属性:字符串)=>void
}
类MyClass扩展了events.EventEmitter{
private\u untypedOn=this.on
private _untypedEmit=this.emit
public on=(事件:K,侦听器:IEmissions[K]):this=>this.\u untypedOn(事件,侦听器)
public emit=(事件:K,…args:Parameters):布尔=>this.\u untypedEmit(事件,…args)
this.emit('test','Testing')//这将为您键入!
}
//例如:
const inst=新的MyClass()
inst.on('test',info=>console.log(info))//这将被键入!
您可以使用它

例如:

从'tsee'导入{EventEmitter};
const events=new EventEmitter void,
}>();
//foo的参数是完全类型检查的
emit('foo',123,'helloworld');

该软件包还提供接口和一些UTIL。

扩展@SergeyK的答案,使用它,您可以在
emit
函数上进行类型检查和完成,而无需重复事件类型

  • 为每个事件类型定义事件侦听器签名:
  • 声明接口,该接口基于EventListeners(
    MyClassEvents
    )函数签名为
    MyClass
    构造类型:

  • 现在,您将在
    emit函数上进行类型检查:

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

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

    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();
      }
    }
    
    从“微型发射器”导入{TypedEmitter};
    接口MyClassEvents{
    'add':(el:string,wasNew:boolean)=>void;
    'delete':(changedCount:number)=>void;
    }
    类MyClass扩展了TypeDemiter{
    构造函数(){
    超级();
    }
    }
    
    发生了什么错误?而且您的
    on
    方法似乎缺少主体。正如@NitzanTomer所说,要么您的
    on
    方法缺少主体,要么您希望将
    事件
    参数声明为
    'hello'
    以外的其他类型。应该对你有帮助。只需将更新1作为答案,因为另一种方式更麻烦。这太棒了,我喜欢你的软件包!那个包裹真是太棒了。到目前为止,这是我见过的最人性化的解决方案。谢谢大家!@MaxTruxa很高兴您发现它很有用:)这正是我所需要的。这样就可以在仍然强制键入的情况下重写函数。
    interface MyClassEvents {
      'add': (el: string, wasNew: boolean) => void;
      'delete': (changedCount: number) => void;
    }
    
    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;
    }
    
    class MyClass extends EventEmitter {
      constructor() {
        super();
      }
    }
    
    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();
      }
    }