Type-Safe Event Map Emitter

Bind event names to their payload types in one map so listeners and emitters are checked together and misspelled events fail to compile.

TypescriptResilience

Code

snippet
type EventMap = {
  login: { userId: string };
  logout: { userId: string; reason: string };
  error: { message: string; retryable: boolean };
};

export class TypedEmitter<M extends Record<string, unknown>> {
  private handlers: { [K in keyof M]?: Array<(payload: M[K]) => void> } = {};

  on<K extends keyof M>(event: K, handler: (payload: M[K]) => void): void {
    (this.handlers[event] ??= []).push(handler);
  }

  emit<K extends keyof M>(event: K, payload: M[K]): void {
    for (const handler of this.handlers[event] ?? []) handler(payload);
  }
}

export const emitter = new TypedEmitter<EventMap>();