@posva/event-emitter
Version:
Type safe and light event emitter / pubsub class
1 lines • 6.23 kB
Source Map (JSON)
{"version":3,"sources":["../src/index.ts","../src/event-emitter.ts"],"sourcesContent":["export { EventEmitter } from './event-emitter'\n\nexport type {\n EventHandlerMap,\n EventType,\n GenericEventMap,\n GenericEventHandler,\n\n // internals prefixed with _\n ToTuple as _ToTuple,\n WildcardHandler as _WildcardHandler,\n RemoveEventListener as _RemoveEventListener,\n EventHandlerList as _EventHandlerList,\n WildCardEventHandlerList as _WildCardEventHandlerList,\n Handler as _Handler,\n} from './event-emitter'\n","/**\n * Valid event tyes.\n */\nexport type EventType = string | symbol\n\n/**\n * Generic event map used for type checking.\n */\nexport type GenericEventMap = Record<EventType, unknown>\n\n/**\n * Event handler function. Transforms tuples into rest parameters.\n * @internal\n */\nexport type Handler<Payload> = (...payload: ToTuple<Payload>) => void\n\n/**\n * Convenience type for a list of event handlers.\n * @internal\n */\nexport type EventHandlerList<Payload = unknown> = Handler<Payload>[]\n\n/**\n * Convenience type for a list of wildcard event handlers.\n * @internal\n */\nexport type WildCardEventHandlerList<EventMap extends GenericEventMap> =\n WildcardHandler<EventMap>[]\n\n/**\n * Map of event names to registered handler functions.\n */\nexport type EventHandlerMap<EventMap extends GenericEventMap> = Map<\n keyof EventMap | '*',\n GenericEventHandler<EventMap>[]\n>\n\n/**\n * Event handler function for a specific event type.\n */\nexport type GenericEventHandler<EventMap extends GenericEventMap> =\n | Handler<EventMap[keyof EventMap]>\n | WildcardHandler<EventMap>\n\n/**\n * Convenience type for the returned function of `on`.\n * @internal\n */\nexport type RemoveEventListener = () => void\n\n/**\n * Event handler function for the `'*'` event type.\n * @internal\n */\nexport type WildcardHandler<EventMap extends GenericEventMap> = (\n ...args: {\n [Event in keyof EventMap]: [type: Event, payloads: ToTuple<EventMap[Event]>]\n }[keyof EventMap]\n) => void\n\n/**\n * Transforms a non tuple into a tuple with the value but keeps tuples as is.\n * @internal\n */\nexport type ToTuple<T> = T extends [unknown, ...unknown[]] | [] ? T : [T]\n\n/**\n * Event emitter class.\n */\nexport class EventEmitter<Events extends GenericEventMap> {\n /**\n * A Map of event names to registered handler functions.\n */\n all: EventHandlerMap<Events>\n\n constructor(all?: EventHandlerMap<Events>) {\n this.all = all || new Map()\n }\n\n /**\n * Register an event handler for the given type.\n * @param type Type of event to listen for, or `'*'` for all events\n * @param handler Function to call in response to given event\n */\n on<Key extends keyof Events>(\n type: Key,\n handler: Handler<Events[Key]>,\n ): RemoveEventListener\n /**\n * Register an event handler for all events.\n * @param type `'*'`\n * @param handler Function to call in response to given event\n */\n on(type: '*', handler: WildcardHandler<Events>): RemoveEventListener\n on(\n type: EventType,\n handler: GenericEventHandler<Events>,\n ): RemoveEventListener {\n if (!this.all.has(type)) {\n this.all.set(type, [])\n }\n const handlers: Array<GenericEventHandler<Events>> = this.all.get(type)!\n handlers.push(handler)\n\n return () => handlers.splice(handlers.indexOf(handler) >>> 0, 1)\n }\n\n /**\n * Remove an event handler for the given type.\n * If `handler` is omitted, all handlers of the given type are removed.\n * @param type Type of event to unregister `handler` from, or `'*'`\n * @param handler Handler function to remove\n */\n off<Key extends keyof Events>(type: Key, handler?: Handler<Events[Key]>): void\n off(type: '*', handler?: WildcardHandler<Events>): void\n /**\n * Remove all event handlers.\n */\n off(): void\n off(type?: EventType, handler?: GenericEventHandler<Events>): void {\n if (!type) {\n return this.all.clear()\n }\n\n const handlers: Array<GenericEventHandler<Events>> | undefined =\n this.all.get(type)\n if (handlers) {\n if (handler) {\n handlers.splice(handlers.indexOf(handler) >>> 0, 1)\n } else {\n this.all.delete(type)\n }\n }\n }\n\n /**\n * Invoke all handlers for the given type.\n * If present, `'*'` handlers are invoked after type-matched handlers.\n *\n * Note: Manually firing `'*'` handlers is not supported.\n *\n * @param type The event type to invoke\n * @param payload Any value to each handler\n */\n emit<Key extends keyof Events>(\n type: Key,\n ...payload: ToTuple<Events[Key]>\n ): void {\n let handlers:\n | EventHandlerList<Events[keyof Events]>\n | WildCardEventHandlerList<Events>\n | undefined = this.all.get(type) as\n | EventHandlerList<Events[keyof Events]>\n | undefined\n\n // copy to trigger handlers even if they are removed\n handlers?.slice().map((handler) => {\n handler(...payload)\n })\n\n handlers = this.all.get('*') as WildCardEventHandlerList<Events> | undefined\n if (handlers) {\n handlers.slice().map((handler) => {\n handler(type, payload)\n })\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACqEO,IAAM,eAAN,MAAmD;AAAA;AAAA;AAAA;AAAA,EAIxD;AAAA,EAEA,YAAY,KAA+B;AACzC,SAAK,MAAM,OAAO,oBAAI,IAAI;AAAA,EAC5B;AAAA,EAiBA,GACE,MACA,SACqB;AACrB,QAAI,CAAC,KAAK,IAAI,IAAI,IAAI,GAAG;AACvB,WAAK,IAAI,IAAI,MAAM,CAAC,CAAC;AAAA,IACvB;AACA,UAAM,WAA+C,KAAK,IAAI,IAAI,IAAI;AACtE,aAAS,KAAK,OAAO;AAErB,WAAO,MAAM,SAAS,OAAO,SAAS,QAAQ,OAAO,MAAM,GAAG,CAAC;AAAA,EACjE;AAAA,EAcA,IAAI,MAAkB,SAA6C;AACjE,QAAI,CAAC,MAAM;AACT,aAAO,KAAK,IAAI,MAAM;AAAA,IACxB;AAEA,UAAM,WACJ,KAAK,IAAI,IAAI,IAAI;AACnB,QAAI,UAAU;AACZ,UAAI,SAAS;AACX,iBAAS,OAAO,SAAS,QAAQ,OAAO,MAAM,GAAG,CAAC;AAAA,MACpD,OAAO;AACL,aAAK,IAAI,OAAO,IAAI;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,KACE,SACG,SACG;AACN,QAAI,WAGY,KAAK,IAAI,IAAI,IAAI;AAKjC,cAAU,MAAM,EAAE,IAAI,CAAC,YAAY;AACjC,cAAQ,GAAG,OAAO;AAAA,IACpB,CAAC;AAED,eAAW,KAAK,IAAI,IAAI,GAAG;AAC3B,QAAI,UAAU;AACZ,eAAS,MAAM,EAAE,IAAI,CAAC,YAAY;AAChC,gBAAQ,MAAM,OAAO;AAAA,MACvB,CAAC;AAAA,IACH;AAAA,EACF;AACF;","names":[]}