type Type = string | number | symbol type Handler = (event: { target: T1 type: T2 } & T3) => any type Options = { once: boolean } export default class Emitter> { private readonly Emitter$items: [ name: Type, listener: any, options?: Options ][] = [] public on(name: U, handler: Handler, options?: Options): void { this.off(name, handler); this.Emitter$items.push([name, handler, { once: !!options?.once, },]); } public off(name: U, handler?: Handler): void { for (let a = this.Emitter$items, i = 0; a.length > i; i++) { if ("*" === name || (a[i][0] === name && a[i][1] === handler)) { a.splice(i--, 1); } } } public emit(name: U, event: T2[U]): void { this.Emitter$items.forEach((entry) => { if (name === entry[0]) { entry[1]({ ...event, target: this, type: name, }); if (entry[2]?.once) this.off(name, entry[1]); } }); } }