73 lines
2.3 KiB
TypeScript
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);
|
|
}
|
|
}
|