TypeScript Academy · Lektion

Generisk event emitter-klass

Bygg en återanvändbar, typad event emitter från grunden.

Lektion 3 av 413 steg

Generisk event emitter-klass är en gratis lektion i TypeScript Academy på CoddyKit. Detta är lektion 3 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för TypeScript Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i TypeScript Academy innehåller totalt 4 lektioner.

Mål: En TypedEmitter-klass

Vi ska bygga en återanvändbar TypedEmitter<E>-klass som är generisk med avseende på en eventkarta E, med fullständigt typade metoder för on, off och emit.

interface Events { login: { userId: string }; logout: void }
// class TypedEmitter<Events> will manage handlers safely.
console.log("building a typed emitter");

Ett typalias för handlers

Definiera en handlertyp som parametriseras med eventnamnet, så att varje listener tar emot rätt payload.

type Handler<E, K extends keyof E> = (payload: E[K]) => void;
// E[K] is the payload type for event K in map E.
console.log("handler typed by E[K]");

Map för listeners

Lagra handlers med eventnamnet som nyckel. En mappad typ ger varje nyckel en array med korrekt typade handlers.

class TypedEmitter<E> {
  private listeners: { [K in keyof E]?: Array<(p: E[K]) => void> } = {};
}
console.log("listeners map ready");

Implementera on

Metoden on lägger till en handler i arrayen för dess event och skapar arrayen första gången den används.

class TypedEmitter<E> {
  private listeners: { [K in keyof E]?: Array<(p: E[K]) => void> } = {};
  on<K extends keyof E>(event: K, handler: (p: E[K]) => void): void {
    (this.listeners[event] ||= []).push(handler);
  }
}
console.log("on implemented");

Implementera emit

Metoden emit slår upp handlers för eventet och anropar var och en med den typade payloaden.

class TypedEmitter<E> {
  private listeners: { [K in keyof E]?: Array<(p: E[K]) => void> } = {};
  on<K extends keyof E>(e: K, h: (p: E[K]) => void) { (this.listeners[e] ||= []).push(h); }
  emit<K extends keyof E>(e: K, payload: E[K]): void {
    (this.listeners[e] || []).forEach(h => h(payload));
  }
}
console.log("emit implemented");

Implementera off

Metoden off tar bort en tidigare registrerad handler genom att filtrera bort den från arrayen.

class TypedEmitter<E> {
  private listeners: { [K in keyof E]?: Array<(p: E[K]) => void> } = {};
  on<K extends keyof E>(e: K, h: (p: E[K]) => void) { (this.listeners[e] ||= []).push(h); }
  off<K extends keyof E>(e: K, h: (p: E[K]) => void) {
    this.listeners[e] = (this.listeners[e] || []).filter(x => x !== h);
  }
}
console.log("off implemented");

Sätt ihop klassen

Här är hela klassen med alla tre metoder, generisk för alla eventkartor du anger.

class TypedEmitter<E> {
  private listeners: { [K in keyof E]?: Array<(p: E[K]) => void> } = {};
  on<K extends keyof E>(e: K, h: (p: E[K]) => void) { (this.listeners[e] ||= []).push(h); }
  off<K extends keyof E>(e: K, h: (p: E[K]) => void) { this.listeners[e] = (this.listeners[e] || []).filter(x => x !== h); }
  emit<K extends keyof E>(e: K, p: E[K]) { (this.listeners[e] || []).forEach(h => h(p)); }
}
console.log("TypedEmitter complete");

Använda TypedEmitter

Skapa en instans med en konkret eventkarta. Nu är on och emit fullständigt typade för dessa event.

class TypedEmitter<E> {
  private listeners: { [K in keyof E]?: Array<(p: E[K]) => void> } = {};
  on<K extends keyof E>(e: K, h: (p: E[K]) => void) { (this.listeners[e] ||= []).push(h); }
  emit<K extends keyof E>(e: K, p: E[K]) { (this.listeners[e] || []).forEach(h => h(p)); }
}
interface Events { login: { userId: string } }
const bus = new TypedEmitter<Events>();
bus.on("login", p => console.log("hi", p.userId));
bus.emit("login", { userId: "u1" });

Typfel upptäcks

Klassen avvisar okända event och felaktiga payloads vid kompileringen, precis som de fristående funktionerna gjorde.

class TypedEmitter<E> {
  private listeners: { [K in keyof E]?: Array<(p: E[K]) => void> } = {};
  on<K extends keyof E>(e: K, h: (p: E[K]) => void) { (this.listeners[e] ||= []).push(h); }
  emit<K extends keyof E>(e: K, p: E[K]) { (this.listeners[e] || []).forEach(h => h(p)); }
}
interface Events { ping: { at: number } }
const bus = new TypedEmitter<Events>();
// bus.emit("pong", { at: 1 }); // Error
bus.emit("ping", { at: 1 });
console.log("typed bus");

Flera handlers per event

Eftersom varje event motsvarar en array kan du registrera många handlers, och alla körs när emit anropas.

class TypedEmitter<E> {
  private listeners: { [K in keyof E]?: Array<(p: E[K]) => void> } = {};
  on<K extends keyof E>(e: K, h: (p: E[K]) => void) { (this.listeners[e] ||= []).push(h); }
  emit<K extends keyof E>(e: K, p: E[K]) { (this.listeners[e] || []).forEach(h => h(p)); }
}
interface Events { tick: { n: number } }
const bus = new TypedEmitter<Events>();
bus.on("tick", p => console.log("a", p.n));
bus.on("tick", p => console.log("b", p.n));
bus.emit("tick", { n: 7 });

En grund du kan bygga vidare på

Den här klassen är en stabil grund. Nästa steg är att förfina inferensen av listenerargument och lägga till semantik för once.

class TypedEmitter<E> {
  private listeners: { [K in keyof E]?: Array<(p: E[K]) => void> } = {};
  on<K extends keyof E>(e: K, h: (p: E[K]) => void) { (this.listeners[e] ||= []).push(h); }
  emit<K extends keyof E>(e: K, p: E[K]) { (this.listeners[e] || []).forEach(h => h(p)); }
}
const bus = new TypedEmitter<{ go: void }>();
bus.on("go", () => console.log("go!"));
bus.emit("go", undefined as void);

Snabbtest: Generisk emitter-klass

Kontrollera din förståelse av den generiska event-emitter-klassen.

Sammanfattning: Generisk event-emitter-klass

Du byggde TypedEmitter<E> med en mappad listenerlagring och fullständigt typade metoder för on, off och emit. Det ger en återanvändbar, typsäker pub/sub för alla eventkartor.

class TypedEmitter<E> {
  private listeners: { [K in keyof E]?: Array<(p: E[K]) => void> } = {};
  on<K extends keyof E>(e: K, h: (p: E[K]) => void) { (this.listeners[e] ||= []).push(h); }
  emit<K extends keyof E>(e: K, p: E[K]) { (this.listeners[e] || []).forEach(h => h(p)); }
}
const bus = new TypedEmitter<{ hi: { name: string } }>();
bus.on("hi", p => console.log(p.name));
bus.emit("hi", { name: "Ada" });
Gratis att börja

Lär dig TypeScript med en AI-lärare – gratis

Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.

Kurser
101
Lektioner
352

Vanliga frågor

Är lektionen ”Generisk event emitter-klass” gratis?

Ja – hela texten till ”Generisk event emitter-klass” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i TypeScript Academy, kan Ni uppgradera till CoddyKit PRO. Kursen i TypeScript Academy innehåller totalt 4 lektioner.

Vad lär jag mig i ”Generisk event emitter-klass”?

Bygg en återanvändbar, typad event emitter från grunden. Ni övar på TypeScript Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.

Behöver jag någon erfarenhet för att börja lära mig TypeScript Academy?

Du behöver inga förkunskaper. Utbildningen i TypeScript Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 3 av 4.

Hur lång tid tar lektionen ”Generisk event emitter-klass”?

De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.

Kan jag skriva och köra kod i den här TypeScript Academy-lektionen?

Ja. Varje TypeScript Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.

Alla lektioner i den här kursen

  1. Typbestämning av händelsekartor
  2. Typsäkra emit och on
  3. Generisk event emitter-klass
  4. Inferens av lyssnarargument
← Tillbaka till TypeScript Academy