typing eventhandler in typescript
I came across this issue when I made a type definition file for the upcoming web-ble functionalities in chrome and edge browser (more about it).
the challenge#
The challenge is the following:
- there are n-events we can register to trough a function
addEventhandler
- in the callback we get data back
- depending on the event we register to, we expect a typed callback
untyped example:
MyObject.addEventhandler("eventA", myCallback, options);
function myCallback(event: any) {
// do something here
}
solution#
mapped types#
Mapping Types are great if we want determine the type based on a single key.
type MyObject = {
name: string;
age: number;
};
function get<>();
define possible callbacks#
type MyEventsMap = {
eventA: (event: EventDataA) => void;
eventB: (event: EventDataB) => void;
};
full code example#
With direct implementation:
// define event data
type EventDataA = "EventDataA";
type EventDataB = "EventDataB";
// setup mapping
type MyEventsMap = {
eventA: (event: EventDataA) => void;
eventB: (event: EventDataB) => void;
};
// create callbacks
const handlerA: MyEventsMap["eventA"] = (event: EventDataA) => {};
const handlerB: MyEventsMap["eventB"] = (event: EventDataB) => {};
// function definition - possibility 1
function addEventhandler<K extends keyof MyEventsMap>(eventName: K, func: MyEventsMap[K]) {
// implementation details
}
addEventhandler("eventA", (event: EventDataA) => {});
addEventhandler("eventA", handlerA);
Alternative to direct implementation trough typed arrow function:
// function definition implementing type - possibility 2
type MyTypeFunction<Type> = {
<K extends keyof Type>(eventName: K, event: Type[K]): void;
};
const addEventhandler2: MyTypeFunction<MyEventsMap> = () => {
// implementation details
};
addEventhandler2("eventB", (event: EventDataB) => {});
addEventhandler("eventB", handlerB);
Here is the full code example in action TS Playground Link