interface EventListener { callback: (payload: T) => void; target?: unknown; once: boolean; } export class EventManager> { private readonly listeners = new Map>(); on(event: K, callback: (payload: TEvents[K]) => void, target?: unknown): void { this.add(event, callback, target, false); } once(event: K, callback: (payload: TEvents[K]) => void, target?: unknown): void { this.add(event, callback, target, true); } off(event: K, callback: (payload: TEvents[K]) => void, target?: unknown): void { const bucket = this.listeners.get(event); if (!bucket) return; for (const listener of bucket) { if (listener.callback === callback && listener.target === target) { bucket.delete(listener); } } if (bucket.size === 0) this.listeners.delete(event); } offTarget(target: unknown): void { for (const [event, bucket] of this.listeners) { for (const listener of bucket) { if (listener.target === target) bucket.delete(listener); } if (bucket.size === 0) this.listeners.delete(event); } } emit(event: K, payload?: TEvents[K]): void { const bucket = this.listeners.get(event); if (!bucket) return; for (const listener of bucket.values()) { try { (listener.callback as (value: TEvents[K]) => void).call(listener.target, payload); } catch (error) { console.error(`[EventManager] listener failed: ${String(event)}`, error, listener); } if (listener.once) bucket.delete(listener); } if (bucket.size === 0) this.listeners.delete(event); } clear(): void { this.listeners.clear(); } private add(event: K, callback: (payload: TEvents[K]) => void, target: unknown, once: boolean): void { if (typeof callback !== 'function') { console.error(`[EventManager] ignored invalid listener: ${String(event)}`); return; } let bucket = this.listeners.get(event); if (!bucket) { bucket = new Set(); this.listeners.set(event, bucket); } for (const listener of bucket) { if (listener.callback === callback && listener.target === target) return; } bucket.add({ callback: callback as (payload: unknown) => void, target, once }); } }