export type Callback = (...args: ArgsType) => K; export type ArgsType = T extends Array ? T : Array; export class SyncHook { type = ''; listeners = new Set>(); constructor(type?: string) { if (type) { this.type = type; } } on(fn: Callback): void { if (typeof fn === 'function') { this.listeners.add(fn); } } once(fn: Callback): void { // eslint-disable-next-line @typescript-eslint/no-this-alias const self = this; this.on(function wrapper(...args) { self.remove(wrapper); // eslint-disable-next-line prefer-spread return fn.apply(null, args); }); } emit(...data: ArgsType): void | K | Promise { let result; if (this.listeners.size > 0) { // eslint-disable-next-line prefer-spread this.listeners.forEach((fn) => { result = fn(...data); }); } return result; } remove(fn: Callback): void { this.listeners.delete(fn); } removeAll(): void { this.listeners.clear(); } }