/** * fully typed node-like event emitter * usage: `EventEmitter<{ event: eventDataType }>` */ export class EventEmitter { private listeners: { [E in keyof T]: Set<((data: T[E]) => void)> } = Object.create(null) public on(event: E, listener: ((data: T[E]) => void)) { this.listeners[event] ||= new Set() this.listeners[event].add(listener) } public off(event: E, listener: ((data: T[E]) => void)) { this.listeners[event]?.delete(listener) if(this.listeners[event]?.size === 0) { delete this.listeners[event] } } public once(event: E, listener: ((data: T[E]) => void)) { const wrapped = (data: T[E]) => { this.off(event, wrapped) listener(data) } this.on(event, wrapped) } protected emit(event: E, data: T[E]) { if(!this.listeners[event]) return for(const listener of this.listeners[event]) { listener(data) } } }