typescript / expert
Snippet
Typ-sichere Ereignis-Listener-Tupel-Invarianz-Erzwingung
Dieses Beispiel zeigt, wie Sie zugeordnete Typen-Indexzugriffe, generische Constraints und variadische Tupeltypen nutzen, um einen strikt typisierten Event-Emitter zu erstellen. Event-Nutzdaten werden als Tupel deklariert, sodass Handler-Funktionssignaturen und `emit`-Argumente zur Kompilierzeit ohne Type Assertions überprüft werden.
snippet.ts
typescript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
type EventMap = {userLogin: [userId: string, timestamp: number];dataSync: [status: 'pending' | 'complete', payload: ReadonlyArray<number>];};type EventListener<T extends unknown[]> = (...args: T) => void | Promise<void>;class TypedEventEmitter<E extends Record<string, unknown[]>> {private listeners: { [K in keyof E]?: Array<EventListener<E[K]>> } = {};on<K extends keyof E>(event: K, listener: EventListener<E[K]>): void {(this.listeners[event] ??= []).push(listener);}async emit<K extends keyof E>(event: K, ...args: E[K]): Promise<void> {const handlers = this.listeners[event] ?? [];await Promise.all(handlers.map((fn) => fn(...args)));}}
Erklärung
1
type EventMap = { ... };
Definiert eine zentrale Zuordnungs-Map, die Event-Namen mit Tupel-Typen für Parameterlisten verknüpft.
2
type EventListener<T extends unknown[]> = (...args: T) => void | Promise<void>;
Nutzt variadische Tupel-Typen, um generische Tupel direkt in stark typisierte Funktionsparameter umzuwandeln.
3
private listeners: { [K in keyof E]?: Array<EventListener<E[K]>> } = {};
Erstellt ein Mapped-Type-Dictionary mit Arrays typisierter Listener, indiziert über Event-Schlüssel.
4
on<K extends keyof E>(event: K, listener: EventListener<E[K]>): void
Beschränkt die Event-Registrierung auf gültige Schlüssel von E und erzwingt exakte Parameterübereinstimmung.
5
async emit<K extends keyof E>(event: K, ...args: E[K]): Promise<void>
Verwendet Tupel-Expansion in Rest-Parametern, um Nutzdaten-Argumente beim Auslösen zur Kompilierzeit zu prüfen.