export type EventCallback = (e?: T) => void | Promise; export type EventStackItem = { isOnce: boolean; cb: EventCallback; }; export type EventStack = { [key: string]: Array>; }; export class EventEmitter { eventStack: EvStack; protected _emitEvent( key: K, event?: Parameters[0] ) { const stack = this.eventStack[key]; stack.forEach((st) => { st.cb(event); if (st.isOnce) this.off(key, st.cb); }); } on( eventName: K, callback: EvStack[K][number]['cb'] ) { this.eventStack[eventName].push({ isOnce: false, cb: callback }); } once( eventName: K, callback: EvStack[K][number]['cb'] ) { this.eventStack[eventName].push({ isOnce: true, cb: callback }); } off( eventName: K, callback: EvStack[K][number]['cb'] ) { const idx = this.eventStack[eventName].findIndex( (st) => st.cb === callback ); if (idx >= 0) this.eventStack[eventName].splice(idx, 1); } constructor(stack: EvStack) { this.eventStack = stack; } }