Typisierter EventEmitter
Die Klasse Emitter<Events> bekommt eine Beschreibung ihrer Events: new Emitter<{ login: { userId: number }; message: string }>(). on(event, handler) meldet einen Handler an und liefert eine Funktion zum Abmelden, emit(event, payload) ruft die Handler dieses Events auf.
Mach die Typen genau: ein Eventname kann nur einer der Schlüssel von Events sein, und der Typ von payload im Handler und in emit kommt von genau diesem Event.
Strg+Enter führt die Tests aus. Tab rückt ein; um den Editor per Tastatur zu verlassen, drücke Esc und dann Tab. Der Code wird in diesem Browser gespeichert.
Tests (7)
Typtests prüft der TypeScript-Compiler im strict-Modus. Expect<Equal<A, B>> besteht, wenn die Typen exakt gleich sind, und // @ts-expect-error, wenn die nächste Zeile nicht kompiliert. Der erste Start lädt den Compiler und dauert daher ein paar Sekunden.
- Typen
type E = { login: { userId: number }; message: string }; const e = new Emitter<E>(); e.on('login', (payload) => { type _ = Expect<Equal<typeof payload, { userId: number }>>; });
- Typen
type E = { login: { userId: number }; message: string }; const e = new Emitter<E>(); // @ts-expect-error - message carries a string e.emit('message', 42);
- Typen
type E = { login: { userId: number }; message: string }; const e = new Emitter<E>(); // @ts-expect-error - there is no such event e.on('signup', () => {});
const e = new Emitter(); const a = fn(); const b = fn(); e.on('message', a); e.on('message', b); e.emit('message', 'hi'); expect(a).toHaveBeenCalledWith('hi'); expect(b).toHaveBeenCalledWith('hi');
const e = new Emitter(); const h = fn(); const off = e.on('login', h); e.emit('login', { userId: 1 }); off(); e.emit('login', { userId: 2 }); expect(h).toHaveBeenCalledTimes(1); expect(h).toHaveBeenLastCalledWith({ userId: 1 });
const e = new Emitter(); expect(() => e.emit('nobody-listens', 1)).not.toThrow();
const e = new Emitter(); const a = fn(); const b = fn(); e.on('x', a); e.on('y', b); e.emit('x', 1); expect(a).toHaveBeenCalledTimes(1); expect(b).toHaveBeenCalledTimes(0);