Files
Vectrace/src/utils/eventEmitter.ts
T
2026-06-29 09:40:34 +02:00

73 lines
2.3 KiB
TypeScript

import { pushUnique, removeItem } from "./collection";
export type EventMap<T> = Record<keyof T, any[]> | never;
export type DefaultEventMap = [never];
export type AnyRest = [...args: any[]];
export type Args<K, T> = T extends DefaultEventMap ? AnyRest : K extends keyof T ? T[K] : never;
export type Key<K, T> = T extends DefaultEventMap ? number : K | keyof T;
export type Listener<K, T, F> = T extends DefaultEventMap
? F
: K extends keyof T
? T[K] extends unknown[]
? (...args: T[K]) => void
: never
: never;
export type Listener1<K, T> = Listener<K, T, (...args: any[]) => void>;
export class BasicEventEmitter<T extends EventMap<T>> {
private listeners = new Map<Key<any, Listener1<any, any>>, any>();
on<K>(eventName: Key<K, T>, listener: Listener1<K, T>): () => void {
const arr = this.listeners.get(eventName) || [];
pushUnique(arr, listener);
this.listeners.set(eventName, arr);
return () => {
this.off(eventName, listener);
};
}
off<K>(eventName: Key<K, T>, listener: Listener1<K, T>): boolean {
const arr = this.listeners.get(eventName) || [];
removeItem(arr, listener);
if (!arr.length) {
this.listeners.delete(eventName);
return true;
}
return false;
}
emit<K>(eventName: Key<K, T>, ...args: Args<K, T>): Promise<unknown> {
const listeners = this.listeners.get(eventName);
const promises: Promise<unknown>[] = [];
if (listeners) {
for (let i = 0; i < listeners.length; i++) {
try {
const listener = listeners[i];
if (listener) {
const result = listener(...args);
if (result instanceof Promise) {
promises.push(result);
}
}
} catch (error) {
console.error(error);
}
}
}
return Promise.all(promises);
}
listenersCount<K>(type: Key<K, T>) {
const arr = this.listeners.get(type);
return arr ? arr.length : 0;
}
removeAllListeners() {
this.listeners.clear();
}
removeSpecificListeners<K>(type: Key<K, T>) {
this.listeners.delete(type);
}
}