/** * Provides a strongly typed event emitter implementation. * * Written in Italy with love, sun and passion, by Massimo Saccani. * * Released under the MIT License. * Use at your own risk; the author assumes no liability for damages. */ import EventEmitter from 'events' // eslint-disable-next-line @typescript-eslint/ban-types export type Constructor = new (...args: any[]) => T export function applyMixin( target: Constructor, mixin: Constructor, includeConstructor = false, ): void { // Figure out the inheritance chain of the mixin const inheritanceChain: Constructor[] = [mixin] // eslint-disable-next-line no-constant-condition while (true) { const current = inheritanceChain[0] const base = Object.getPrototypeOf(current) if (base?.prototype) { inheritanceChain.unshift(base) } else { break } } for (const ctor of inheritanceChain) { for (const prop of Object.getOwnPropertyNames(ctor.prototype)) { // Do not override the constructor if (includeConstructor || prop !== 'constructor') { Object.defineProperty( target.prototype, prop, Object.getOwnPropertyDescriptor(ctor.prototype, prop) ?? Object.create(null), ) } } } } export type EventHandler = // Add more overloads as necessary | ((arg1: any, arg2: any, arg3: any, arg4: any) => void) | ((arg1: any, arg2: any, arg3: any) => void) | ((arg1: any, arg2: any) => void) | ((arg1: any) => void) | ((...args: any[]) => void) export interface TypedEventEmitter< TEvents extends Record, > { on( event: TEvent, callback: TEvents[TEvent], ): this once( event: TEvent, callback: TEvents[TEvent], ): this prependListener( event: TEvent, callback: TEvents[TEvent], ): this prependOnceListener( event: TEvent, callback: TEvents[TEvent], ): this removeListener( event: TEvent, callback: TEvents[TEvent], ): this off( event: TEvent, callback: TEvents[TEvent], ): this removeAllListeners(event?: keyof TEvents): this emit( event: TEvent, ...args: Parameters ): boolean setMaxListeners(n: number): this getMaxListeners(): number listeners( eventName: TEvent, ): TEvents[TEvent][] rawListeners( eventName: TEvent, ): TEvents[TEvent][] listenerCount( event: TEvent, listener?: TEvents[TEvent], ): number eventNames(): Array } // eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging export class TypedEventEmitter< TEvents extends Record, > {} // Make TypedEventEmitter inherit from EventEmitter without actually extending applyMixin(TypedEventEmitter, EventEmitter)