I have a class extends EventEmitter
that can emit event hello
. How can I declare the on
method with specific event name and listener signature?
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; }
You can use typed event emitter package for this. eg: 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');
EventEmitter Class When an EventEmitter instance faces any error, it emits an 'error' event. When a new listener is added, 'newListener' event is fired and when a listener is removed, 'removeListener' event is fired. EventEmitter provides multiple properties like on and emit.
Most usable way of doing this, is to use 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); } }
Note that if you are exporting your class, both the interface and class have to be declared with the export
keyword.
to extend @SergeyK's answer, with this you can get type-checking and completion on both emit
and on
functions without repeating event types.
interface MyClassEvents { 'add': (el: string, wasNew: boolean) => void; 'delete': (changedCount: number) => void; }
MyClass
, based on EventListeners (MyClassEvents
) function signature: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(); } }
Now you will get type checking for on
and emit
functions:
Unfortunately you will get completion and type-checking only on those two functions (unless you define more functions inside MyClass interface).
To get more generic solution, you can use this package. note: it adds no runtime overhead.
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(); } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With