I am using socket.io, so I'm working with an event types object that looks like this:
// these are the possible events. the event name is the key and the event function type is the type
interface Events {
a: () => void;
b: (x: number) => void;
}
The possible events that the socket can emit are a and b. When a is emitted, it's of type () => void, and when b is emitted, it's of type (x: number) => void.
Now I want to make a map where I store multiple callbacks for each event type.
// this gets the event function type based on the event name
type SpecificListenerType<T extends keyof Events> = Pick<Events, T>[T];
// show that it works
let aa: SpecificListenerType<'a'>; // type is () => void
let bb: SpecificListenerType<'b'>; // type is (x: number) => void
// this is a map that stores a list of functions for each event name
type ListenerMap = {
[K in keyof Events]: Array<SpecificListenerType<K>>;
};
// initialize the map to empty lists
const listenerMap: ListenerMap = {a: [], b: []};
// show that it works
let aaa = listenerMap['a']; // type is Array<() => void>
let bbb = listenerMap['b']; // type is Array<(x: number) => void>
That should allow me to map a to a list of void functions with no arguments and b to a list of void functions that have 1 number argument.
Now I want to write the function that removes items from this map.
// function to remove one item from the map
const off = <T extends keyof Events>(
event: T,
listener: SpecificListenerType<T>,
) => {
// what can I do here?
listenerMap[event] = listenerMap[event].filter((registeredListener) => {
return registeredListener !== listener;
});
};
But I cannot assign to the map because the types don't work out. I thought the SpecificListenerType<T> would do the trick here, but I'm not sure why it doesn't. listenerMap[event] should resolve to a single function type, no?