TypeScript Academy · Lekcja

Bezpieczne typowo emit i on

Wymuszaj poprawne dane podczas emitowania i nasłuchiwania zdarzeń

Lekcja 2 z 413 kroki

Bezpieczne typowo emit i on to bezpłatna lekcja TypeScript Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej TypeScript Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs TypeScript Academy zawiera 4 lekcji w sumie.

Bezpieczna typowo sygnatura emit

Należy uczynić emit generycznym względem nazwy zdarzenia K. Parametr payloadu będzie wtedy miał typ Events[K], więc nazwa i payload muszą do siebie pasować.

interface Events { login: { userId: string }; logout: void }
function emit<K extends keyof Events>(event: K, payload: Events[K]) {
  console.log("emit", event, JSON.stringify(payload));
}
emit("login", { userId: "u1" });

Niepoprawny payload powoduje błąd kompilacji

Jeśli payload nie pasuje do nazwy zdarzenia, TypeScript go odrzuci. Typ generyczny wiąże ze sobą oba parametry.

interface Events { login: { userId: string } }
function emit<K extends keyof Events>(event: K, payload: Events[K]) {}
// emit("login", { id: "u1" }); // Error: id is not userId
emit("login", { userId: "u1" });
console.log("ok");

Nieznane nazwy zdarzeń są odrzucane

Ponieważ K extends keyof Events, nie można emitować zdarzenia, którego nie ma w mapie.

interface Events { login: { userId: string } }
function emit<K extends keyof Events>(event: K, payload: Events[K]) {}
// emit("signup", { userId: "x" }); // Error: "signup" not a key
emit("login", { userId: "x" });
console.log("only known events");

Typowane handlery z użyciem on

Metoda on rejestruje handler, którego argument ma dokładnie typ Events[K], dzięki czemu handlery otrzymują poprawnie typowane payloady.

interface Events { login: { userId: string }; logout: void }
function on<K extends keyof Events>(event: K, handler: (payload: Events[K]) => void) {
  console.log("subscribed to", event);
}
on("login", (p) => console.log(p.userId));

Typ argumentu handlera jest wywnioskowany

Nie trzeba opisywać typu parametru handlera — TypeScript wywnioskuje go z nazwy zdarzenia, zapewniając pełne autouzupełnianie wewnątrz ciała handlera.

interface Events { message: { text: string } }
function on<K extends keyof Events>(event: K, handler: (p: Events[K]) => void) {}
on("message", (p) => {
  // p is { text: string }
  console.log(p.text.toUpperCase());
});

Obsługa zdarzeń bez payloadu

W przypadku zdarzeń typu void handler po prostu nie przyjmuje użytecznego argumentu. Jego handler można wywołać bez danych.

interface Events { logout: void }
function on<K extends keyof Events>(event: K, handler: (p: Events[K]) => void) {}
on("logout", () => console.log("logged out"));

Łączenie emit i on

Razem emit i on tworzą typowane rozwiązanie pub/sub. Emitowanie zdarzenia dostarcza jego handlerom poprawnie typowany payload.

interface Events { ping: { at: number } }
type Handler<K extends keyof Events> = (p: Events[K]) => void;
const handlers: { ping: Handler<"ping">[] } = { ping: [] };
function on<K extends keyof Events>(e: K, h: Handler<K>) { handlers[e].push(h as Handler<"ping">); }
function emit<K extends keyof Events>(e: K, p: Events[K]) { handlers[e].forEach(h => h(p as Events["ping"])); }
on("ping", p => console.log("at", p.at));
emit("ping", { at: 5 });

Ograniczanie pozycji payloadu

Typ generyczny gwarantuje, że argument payloadu jest sprawdzany względem wybranego zdarzenia, wykrywając niezgodności w miejscu wywołania, a nie głęboko w handlerze.

interface Events { add: { x: number; y: number } }
function emit<K extends keyof Events>(e: K, p: Events[K]) {
  return e;
}
emit("add", { x: 1, y: 2 });
// emit("add", { x: 1 }); // Error: y missing
console.log("payload checked");

Autouzupełnianie nazw zdarzeń

Ponieważ pierwszy parametr ma typ keyof Events, edytory podpowiadają poprawne nazwy zdarzeń podczas wpisywania wywołania.

interface Events { open: void; close: void }
function emit<K extends keyof Events>(e: K, p: Events[K]) {}
// Typing emit(" suggests "open" and "close"
emit("open", undefined as void);
console.log("autocompleted names");

Dlaczego generyki są tutaj niezbędne

Bez typu generycznego trzeba byłoby utworzyć przeciążenie dla każdego zdarzenia. Jedna generyczna sygnatura automatycznie skaluje się do dowolnej liczby zdarzeń.

interface Events { a: { x: number }; b: { y: string } }
function emit<K extends keyof Events>(e: K, p: Events[K]) { return p; }
console.log(emit("a", { x: 1 }), emit("b", { y: "hi" }));

Wzorzec wielokrotnego użytku

Wzorzec emit<K>(event, payload) i on<K>(event, handler) stanowi podstawę każdego bezpiecznego typowo emitera, który w następnej kolejności zamkniemy w klasie.

interface Events { tick: { n: number } }
function emit<K extends keyof Events>(e: K, p: Events[K]) { return e; }
function on<K extends keyof Events>(e: K, h: (p: Events[K]) => void) { return e; }
console.log(emit("tick", { n: 1 }), on("tick", p => p.n));

Szybkie sprawdzenie: typowane emit i on

Proszę sprawdzić swoją wiedzę na temat bezpiecznych typowo metod emit i on.

Podsumowanie: bezpieczne typowo emit i on

Zbudowali Państwo generyczne sygnatury emit i on, w których payload ma typ Events[K], dzięki czemu nazwy zdarzeń są dostępne w autouzupełnianiu, niepoprawne payloady powodują błędy kompilacji, a argumenty handlerów są wywnioskowywane.

interface Events { login: { userId: string } }
function emit<K extends keyof Events>(e: K, p: Events[K]) { return e; }
console.log(emit("login", { userId: "u1" }));
Bezpłatny start

Ucz się TypeScript dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
101
Lekcje
352

Często zadawane pytania

Czy lekcja „Bezpieczne typowo emit i on” jest bezpłatna?

Tak — pełny tekst „Bezpieczne typowo emit i on” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu TypeScript Academy, przejdź na CoddyKit PRO. Kurs TypeScript Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Bezpieczne typowo emit i on”?

Wymuszaj poprawne dane podczas emitowania i nasłuchiwania zdarzeń Ćwiczysz TypeScript Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć TypeScript Academy?

Nie wymagamy żadnego doświadczenia. TypeScript Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.

Ile czasu zajmuje lekcja „Bezpieczne typowo emit i on”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji TypeScript Academy?

Tak. Każda lekcja TypeScript Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Typowanie map zdarzeń
  2. Bezpieczne typowo emit i on
  3. Generyczna klasa Event Emitter
  4. Wnioskowanie argumentów listenerów
← Powrót do TypeScript Academy