1
0

NanoEmitter.ts 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. import { createNanoEvents, type DefaultEvents, type Emitter, type EventsMap, type Unsubscribe } from "nanoevents";
  2. export interface NanoEmitterOptions {
  3. /** If set to true, allows emitting events through the public method emit() */
  4. publicEmit: boolean;
  5. }
  6. /** Class that can be extended or instantiated by itself to create an event emitter with helper methods and a strongly typed event map */
  7. export class NanoEmitter<TEvtMap extends EventsMap = DefaultEvents> {
  8. protected readonly events: Emitter<TEvtMap> = createNanoEvents<TEvtMap>();
  9. protected eventUnsubscribes: Unsubscribe[] = [];
  10. protected emitterOptions: NanoEmitterOptions;
  11. constructor(options: Partial<NanoEmitterOptions> = {}) {
  12. this.emitterOptions = {
  13. publicEmit: false,
  14. ...options,
  15. };
  16. }
  17. /** Subscribes to an event - returns a function that unsubscribes the event listener */
  18. public on<TKey extends keyof TEvtMap>(event: TKey | "_", cb: TEvtMap[TKey]): () => void {
  19. // eslint-disable-next-line prefer-const
  20. let unsub: Unsubscribe | undefined;
  21. const unsubProxy = (): void => {
  22. if(!unsub)
  23. return;
  24. unsub();
  25. this.eventUnsubscribes = this.eventUnsubscribes.filter(u => u !== unsub);
  26. };
  27. unsub = this.events.on(event, cb);
  28. this.eventUnsubscribes.push(unsub);
  29. return unsubProxy;
  30. }
  31. /** Subscribes to an event and calls the callback or resolves the Promise only once */
  32. public once<TKey extends keyof TEvtMap>(event: TKey | "_", cb?: TEvtMap[TKey]): Promise<Parameters<TEvtMap[TKey]>> {
  33. return new Promise((resolve) => {
  34. // eslint-disable-next-line prefer-const
  35. let unsub: Unsubscribe | undefined;
  36. const onceProxy = ((...args: Parameters<TEvtMap[TKey]>) => {
  37. unsub!();
  38. cb?.(...args);
  39. resolve(args);
  40. }) as TEvtMap[TKey];
  41. unsub = this.on(event, onceProxy);
  42. });
  43. }
  44. /** Emits an event on this instance - Needs `publicEmit` to be set to true in the constructor! */
  45. public emit<TKey extends keyof TEvtMap>(event: TKey, ...args: Parameters<TEvtMap[TKey]>): boolean {
  46. if(this.emitterOptions.publicEmit) {
  47. this.events.emit(event, ...args);
  48. return true;
  49. }
  50. return false;
  51. }
  52. /** Unsubscribes all event listeners */
  53. public unsubscribeAll(): void {
  54. for(const unsub of this.eventUnsubscribes)
  55. unsub();
  56. this.eventUnsubscribes = [];
  57. }
  58. }