Code

type EventMap = Record<string, any>;type EventKey<T extends EventMap> = string & keyof T;type EventReceiver<T> = (params: T) => void;interface Emitter<T extends EventMap> {  on<K extends EventKey<T>>(eventName: K, fn: EventReceiver<T[K]>): void;  off<K extends EventKey<T>>(eventName: K, fn: EventReceiver<T[K]>): void;  emit<K extends EventKey<T>>(eventName: K, data: T[K]): void;  once<K extends EventKey<T>>(eventName: K, fn: EventReceiver<T[K]>): void;}class EventEmitter<T extends EventMap> implements Emitter<T> {  private listeners: {    [K in keyof T]?: Array<EventReceiver<T[K]>>;  } = {};  on<K extends EventKey<T>>(eventName: K, fn: EventReceiver<T[K]>): void {    if (!this.listeners[eventName]) {      this.listeners[eventName] = [];    }    this.listeners[eventName]!.push(fn);  }  off<K extends EventKey<T>>(eventName: K, fn: EventReceiver<T[K]>): void {    const handlers = this.listeners[eventName];    if (handlers) {      this.listeners[eventName] = handlers.filter(f => f !== fn);    }  }  emit<K extends EventKey<T>>(eventName: K, data: T[K]): void {    const handlers = this.listeners[eventName];    if (handlers) {      handlers.forEach(fn => fn(data));    }  }  once<K extends EventKey<T>>(eventName: K, fn: EventReceiver<T[K]>): void {    const onceWrapper = ((data: T[K]) => {      fn(data);      this.off(eventName, onceWrapper);    }) as EventReceiver<T[K]>;    this.on(eventName, onceWrapper);  }}export default EventEmitter;
import EventEmitter from './EventEmitter';interface MyEvents {  'user:login': { userId: string; email: string };  'user:logout': { userId: string };  'message:send': { text: string; timestamp: number };}const emitter = new EventEmitter<MyEvents>();emitter.on('user:login', (data) => {  console.log(`User ${data.userId} logged in with email ${data.email}`);});emitter.once('user:logout', (data) => {  console.log(`User ${data.userId} logged out`);});emitter.emit('user:login', { userId: 'user123', email: '[email protected]' });emitter.emit('message:send', { text: 'Hello, world!', timestamp: Date.now() });

Comments

No comments yet. Be the first!