export interface EventMap { [event: string]: any; } /** * @inline */ export type EventListener = (data: D) => void; abstract class TypedEventEmitter { protected listeners: { [K in keyof E]?: EventListener[] } = {}; /** * Add an event listener, returns a function that can be called to remove the listener * @param event * @param listener */ on(event: T, listener: EventListener) { if (!this.listeners[event]) { this.listeners[event] = []; } this.listeners[event]!.push(listener); return () => { this.off(event, listener); }; } /** * Add an event listener that will be called only once * @param event * @param listener */ once(event: T, listener: EventListener) { const remove = this.on(event, (data) => { remove(); listener(data); }); return remove; } /** * Remove an event listener * @param event * @param listener */ off(event: T, listener: EventListener) { if (!this.listeners[event]) { return; } this.listeners[event] = this.listeners[event]!.filter((l) => l !== listener); } /** * Dispatch an event to all listeners * @param event * @param data */ protected emit(event: T, data: E[T]) { const listeners = this.listeners[event]; if (!listeners) { return; } listeners.forEach((listener) => listener(data)); } } export default TypedEventEmitter;