irclib/src/utility/typed-event-emitter.ts

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];
}
}