'How can I assign a TypeScript type for event payloads for a class like EventEmitter?

I have a class that is just like Node's EventEmitter (it could even be the same class).

How do I type it in such a way that I can specify what the callback type is for each different event name?

For example, I'd like for even "foo" to have a payload of type number, and event "bar" to have a payload of type string, as in:

const emitter = /* get emitter from somewhere. And how would the type definition look like? */

emitter.on('foo', payload => {
  /* type of payload is number, enforced by TypeScript */
  testNumber('foo') // TS error, 'foo' is not a number
  testNumber(payload) // it works, payload is a number
})

emitter.on('bar', payload => {
  /* type of payload is string, enforced by TypeScript */
  testString(5) // TS error, 5 is not a string
  testString(payload) // it works, payload is a string
})

function testNumber( value: number ) {}
function testString( value: string ) {}

How would we define the EventEmitter declaration so that it is possible to define events and their types, and to then let users use those events with the correct type checking?

Maybe there's a way to define the type of EventEmitter such that when I create one I pass a type argument that contains all the expected types?

Is there a way to do it dynamically after creation?



Solution 1:[1]

I'd start off with something like this:

interface Events {
  foo: number
  bar: string
}

interface EventEmitter<T> {
  on<K extends keyof T>(s: K, listener: (v: T[K]) => void): T[K];
}

declare const emitter: EventEmitter<Events>;

emitter.on('foo', (payload: any) => {
  testNumber(payload)
  testString(payload)
});

emitter.on('bar', (payload: any) => {
  testNumber(payload)
  testString(payload)
});

function testNumber( value: number ) {}
function testString( value: string ) {}

Here's an example on TS Playground.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1