TypeScript
Типизированный EventEmitter
Строгая типизация имён событий и их полезной нагрузки — ошибки ловятся при компиляции.
Код
type Listener<T> = (payload: T) => void;
export class EventEmitter<Events extends Record<string, unknown>> {
private listeners: { [K in keyof Events]?: Set<Listener<Events[K]>> } = {};
on<K extends keyof Events>(event: K, listener: Listener<Events[K]>): () => void {
(this.listeners[event] ??= new Set()).add(listener);
return () => this.off(event, listener);
}
once<K extends keyof Events>(event: K, listener: Listener<Events[K]>): void {
const off = this.on(event, (payload) => {
off();
listener(payload);
});
}
off<K extends keyof Events>(event: K, listener: Listener<Events[K]>): void {
this.listeners[event]?.delete(listener);
}
emit<K extends keyof Events>(event: K, payload: Events[K]): void {
this.listeners[event]?.forEach((listener) => listener(payload));
}
}
interface AppEvents {
login: { userId: number; at: Date };
message: { text: string };
}
const bus = new EventEmitter<AppEvents>();
bus.on('login', ({ userId }) => console.log('Вход:', userId));
bus.emit('login', { userId: 1, at: new Date() });
// bus.emit('login', { userId: '1' }); ← ошибка типа на этапе компиляции