Imagine I am developing an event manager for a chat application. Having had success with event maps in the past, I have decided to use them again.
This is the structure of the event map:
interface ChatEventMap {
incomingMessage: string;
newUser: {
name: string;
id: number;
};
}
type EvType = keyof ChatEventMap;
type Ev<T extends EvType> = ChatEventMap[T];
To listen to events, we have an on
function that takes two arguments: the event type
and a callback function that receives the event data.
The implementation looks like this:
function on<T extends EvType>(type: T, callback: (data: Ev<T>) => void) {
// do something
}
on('newUser', user => {
console.log(user.name); // No errors!
});
However, there is now a requirement to listen to ALL events simultaneously. To address this, I considered creating an onEvent
function that only accepts a callback containing the event type and its data.
The issue arises when trying to perform type guarding inside the callback function!
function onEvent(callback: <T extends EvType>(
ev: { type: T; data: ChatEventMap[T] },
) => void) {
// do something
}
onEvent(ev => {
if (ev.type === 'newUser') {
console.log(ev.data.name); // Error: Property 'name' does not exist on type 'ChatEventMap[T]'
}
});
What could be the mistake here?