typescript / expert
Snippet
Strikt typisierter Event-Emitter für reaktive Framework-Engines
Durch die Abbildung generischer Record-Typen auf Event-Namen und Payloads baut dieses Muster einen stark typisierten Event-Kanal auf. Listener erhalten automatisch inferierte Event-Payload-Parameter basierend auf dem Event-Namen-String.
snippet.ts
typescript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
type EventMap = Record<string, any>;class TypedEmitter<Events extends EventMap> {private listeners: {[K in keyof Events]?: Array<(payload: Events[K]) => void>;} = {};on<K extends keyof Events>(event: K, listener: (payload: Events[K]) => void): void {(this.listeners[event] ??= []).push(listener);}emit<K extends keyof Events>(event: K, payload: Events[K]): void {this.listeners[event]?.forEach((cb) => cb(payload));}}interface ApplicationEvents {'user:login': { id: string; timestamp: number };'cart:checkout': { totalAmount: number };}const bus = new TypedEmitter<ApplicationEvents>();bus.on('user:login', (data) => console.log(data.id.toUpperCase()));bus.emit('user:login', { id: 'u_102', timestamp: Date.now() });
Erklärung
1
type EventMap = Record<string, any>;
Basis-Constraint, das erfordert, dass Event-Vertrags-Dictionaries String-Keys auf Payload-Strukturen abbilden.
2
[K in keyof Events]?: Array<(payload: Events[K]) => void>;
Mapped Type, der Listener-Callback-Arrays passend zu jedem registrierten Event-Schlüssel strukturiert.
3
on<K extends keyof Events>(event: K, listener: (payload: Events[K]) => void): void
Schränkt den Event-Namen auf gültige Schlüssel ein und leitet den genauen Callback-Payload-Argumenttyp ab.
4
bus.emit('user:login', { id: 'u_102', timestamp: Date.now() });
Löst das Laufzeit-Emit aus und validiert gleichzeitig die Payload-Form zur Kompilierzeit.