Wzorce
Jak utrzymać każdą nazwę zdarzenia w parze z właściwym ładunkiem i nasłuchiwaczem?
Użyj mapy zdarzeń i jednego parametru klucza, aby nazwa zdarzenia wybierała typ ładunku w obu metodach.
Przepis
type Handler<Events, K extends keyof Events> = (payload: Events[K]) => void type TypedEmitter<Events extends object> = { on<K extends keyof Events>(event: K, handler: Handler<Events, K>): void emit<K extends keyof Events>(event: K, payload: Events[K]): void } type Events = { saved: { id: string } failed: { message: string } } declare const bus: TypedEmitter<Events> bus.on('saved', payload => payload.id) bus.emit('failed', { message: 'offline' })
Build to kompiluje i sprawdza każdy wynik poniżej.
Jak to działa
- 01
K extends keyof Events
Kluczem może być tylko zadeklarowana nazwa zdarzenia.
- 02
payload: Events[K]
Dostęp indeksowany zamienia wybraną nazwę w dokładny ładunek.
Co dostajesz
keyof Events extends 'saved' | 'failed' ? ('saved' | 'failed' extends keyof Events ? true : false) : false
→trueParameters<Handler<Events, 'saved'>>[0]→{ id: string; }Parameters<Handler<Events, 'failed'>>[0]→{ message: string; }
Gdzie to zawodzi
Typ chroni tylko wywołania przechodzące przez ten interfejs. Luźno typowany emiter pod spodem nadal może dostarczyć błędne dane, więc waliduj zdarzenia przekraczające granice procesu lub sieci.
Wniosek
Mapa plus `K extends keyof Map` to standardowy sposób utrzymania nazwy w korelacji z danymi.
