Aby zaimplementować silnie typowany system zdarzeń w TypeScript, możemy wykorzystać generyki do zdefiniowania typów zdarzeń oraz funkcji, które będą je obsługiwać. Stosowanie generyków zapewnia, że zdarzenia i dane przekazywane do funkcji są odpowiednio typowane, co zwiększa bezpieczeństwo kodu.
Przykład:
type EventMap = { 'click': { x: number; y: number; }; 'hover': { element: string; }; }; class EventEmitter<Events extends Record<string, any>> { private listeners: { [K in keyof Events]?: Array<(data: Events[K]) => void> } = {}; on<E extends keyof Events>(event: E, listener: (data: Events[E]) => void) { if (!this.listeners[event]) { this.listeners[event] = []; } this.listeners[event]!.push(listener); } emit<E extends keyof Events>(event: E, data: Events[E]) { this.listeners[event]?.forEach(listener => listener(data)); } } const emitter = new EventEmitter<EventMap>(); emitter.on('click', (data) => { console.log(`Click at (${data.x}, ${data.y})`); }); emitter.emit('click', { x: 100, y: 200 }); // OK emitter.emit('hover', { element: 'button' }); // OK
W tym przykładzie EventMap
definiuje mapowanie nazw zdarzeń na dane, które mają być do nich przypisane. EventEmitter
to klasa generics, która zapewnia silne typowanie dla metod on
i emit
, dzięki czemu nie musimy się martwić o błędy typów przy rejestrowaniu i wywoływaniu zdarzeń.