export type Subscriber = (...args: any[]) => void; export type EventsRecord = Record; /** * @name PubSub * @category Patterns * @description Simple PubSub implementation * * @since 0.0.2 * * @template {EventsRecord} Events */ export class PubSub { /** * Events map * * @private * @type {Map>} */ private events: Map>; /** * Creates an instance of PubSub */ constructor() { this.events = new Map(); } /** * Subscribe to an event * * @template {keyof Events} K * @param {K} event Name of the event * @param {Events[K]} listener Listener function * @returns {this} */ public on(event: K, listener: Events[K]) { const listeners = this.events.get(event); if (listeners) listeners.add(listener); else this.events.set(event, new Set([listener])); return this; } /** * Unsubscribe from an event * * @template {keyof Events} K * @param {K} event Name of the event * @param {Events[K]} listener Listener function * @returns {this} */ public off(event: K, listener: Events[K]) { const listeners = this.events.get(event); if (listeners) listeners.delete(listener); return this; } /** * Subscribe to an event only once * * @template {keyof Events} K * @param {K} event Name of the event * @param {Events[K]} listener Listener function * @returns {this} */ public once(event: K, listener: Events[K]) { const onceListener = (...args: Parameters) => { this.off(event, onceListener as Events[K]); listener(...args); }; this.on(event, onceListener as Events[K]); return this; } /** * Emit an event * * @template {keyof Events} K * @param {K} event Name of the event * @param {...Parameters} args Arguments for the listener * @returns {boolean} */ public emit(event: K, ...args: Parameters) { const listeners = this.events.get(event); if (!listeners) return false; listeners.forEach((listener) => listener(...args)); return true; } /** * Clear all listeners for an event * * @template {keyof Events} K * @param {K} event Name of the event * @returns {this} */ public clear(event: K) { this.events.delete(event); return this; } }