Hello I am facing problem when trying to implement types for TinyEmitter. I need to implement 2 methods. First:
addEventListener(e: string, (...args: any[]) => void): void;
Second:
emit(e: string, ...args: any[]): void;
But this solution is not suggesting event names, and parameters.
I need to define event types, and event arguments. Something like:
type EventMap = [
(e: 'event1', arg1: number, arg2: string, arg3: string) => void,
(e: 'event2', arg1: string, arg2: string) => void,
...
];
Actually i can infer event name by:
type EventParam<I extends number = number> = Parameters<EventMap[I]>[0];
this will infer event type ('event1' | 'event2')
For other parameters i tried:
type EventArgs<I extends number = number> = EventMap[I] extends ((e: EventParam<I>, ...args: infer P) => any ? P : never;
how to implement this for addEventListener and emit functions with type suggestions ?
Thank you in advance for any advice.
The approach I'd recommend is to make a utility interface which maps the name of the event (as a key) to the corresponding list of argument types (as a value):
Then you can define your
addEventListener()andemit()methods as being generic inK, the type of theeargument constrained to be a key ofEventArgs:I'm calling the interface
Foosince it wasn't specified in the question. Then assuming we have an implementation that makes aFoo:We can see that it behaves as desired:
That essentially answers the question which is primarily about typings; still, it can be implemented like this in a fairly type-safe way:
Essentially it just holds onto an object map from event names to arrays of event listeners, and
addEventListenerpushes the listener onto the right array (initializing it first if need be), whileemitcalls the listeners from the right array (unless it doesn't exist).Playground link to code