66 lines
1.7 KiB
TypeScript
66 lines
1.7 KiB
TypeScript
export type EventMap = {
|
|
[key: string]: (...args: any) => void;
|
|
};
|
|
|
|
export class TypedEventEmitter<Events extends EventMap> {
|
|
private _handlers: {
|
|
[x: string]: { fn: (...args: any) => void; once: boolean }[];
|
|
} = {};
|
|
|
|
addListener<E extends keyof Events>(event: E, fn: Events[E], once = false) {
|
|
if (typeof fn !== 'function') {
|
|
return;
|
|
}
|
|
|
|
if (!this._handlers[event as string]) {
|
|
this._handlers[event as string] = [];
|
|
}
|
|
|
|
this._handlers[event as string].push({ fn, once });
|
|
}
|
|
|
|
on<E extends keyof Events>(event: E, fn: Events[E]) {
|
|
this.addListener<E>(event, fn, false);
|
|
}
|
|
|
|
once<E extends keyof Events>(event: E, fn: Events[E]) {
|
|
this.addListener<E>(event, fn, true);
|
|
}
|
|
|
|
emit<E extends keyof Events>(event: E, ...args: Parameters<Events[E]>): void {
|
|
if (!this._handlers[event as string]) {
|
|
return;
|
|
}
|
|
|
|
this._handlers[event as string]
|
|
.filter((handler) => handler && typeof handler.fn === 'function')
|
|
.forEach((handler) => {
|
|
handler.fn(...(args as []));
|
|
if (handler.once) {
|
|
this.removeEventListener(event, handler.fn as Events[E]);
|
|
}
|
|
});
|
|
}
|
|
|
|
removeEventListener<E extends keyof Events>(event: E, fn: Events[E]): void {
|
|
if (!this._handlers[event as string] || typeof fn !== 'function') {
|
|
return;
|
|
}
|
|
|
|
const indexOf = this._handlers[event as string].findIndex(
|
|
(entry) => entry.fn === fn,
|
|
);
|
|
if (indexOf > -1) {
|
|
this._handlers[event as string].splice(indexOf, 1);
|
|
}
|
|
}
|
|
|
|
removeAllListeners<E extends keyof Events>(event: E): void {
|
|
if (!this._handlers[event as string]) {
|
|
return;
|
|
}
|
|
|
|
delete this._handlers[event as string];
|
|
}
|
|
}
|