0Pricing
TypeScript Academy · Lekcja

Modelowanie automatów stanów

Reprezentuj skończone stany za pomocą unii rozróżnianych

Modelowanie automatów stanów to bezpłatna lekcja TypeScript Academy na CoddyKit. To lekcja 4 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.

Stany jako unia dyskryminowana

Interfejsy użytkownika i przepływy asynchroniczne mają odrębne stany: bezczynny, ładowanie, powodzenie i błąd. Modelowanie ich jako unii dyskryminowanej sprawia, że każdy stan zawiera dokładnie te dane, których potrzebuje.

type State =
  | { status: "idle" }
  | { status: "loading" }
  | { status: "success"; data: string }
  | { status: "error"; message: string };

const s: State = { status: "idle" };
console.log(s.status);

Dane właściwe dla każdego stanu

Tylko stan success ma pole data, a tylko stan error ma pole message. Stany idle i loading nie zawierają dodatkowych danych, co zapobiega przedostawaniu się nieaktualnych danych między stanami.

type State =
  | { status: "idle" }
  | { status: "loading" }
  | { status: "success"; data: number[] }
  | { status: "error"; message: string };

const ok: State = { status: "success", data: [1, 2, 3] };
console.log(ok.status, "data" in ok ? ok.data : null);

Renderowanie każdego stanu

Funkcja przełączająca się na podstawie właściwości status może wygenerować odpowiedni wynik dla każdego stanu, przy czym pola elementu są dostępne tylko tam, gdzie rzeczywiście istnieją.

type State =
  | { status: "idle" }
  | { status: "loading" }
  | { status: "success"; data: string }
  | { status: "error"; message: string };

function view(s: State): string {
  switch (s.status) {
    case "idle": return "Ready";
    case "loading": return "Loading...";
    case "success": return "Got: " + s.data;
    case "error": return "Failed: " + s.message;
  }
}
console.log(view({ status: "success", data: "users" }));

Definiowanie przejść

Maszyna stanów przechodzi między stanami za pomocą przejść. Funkcja przejścia przyjmuje bieżący stan i zdarzenie, a następnie zwraca kolejny stan.

type State =
  | { status: "idle" }
  | { status: "loading" }
  | { status: "success"; data: string }
  | { status: "error"; message: string };

function start(s: State): State {
  if (s.status === "idle") return { status: "loading" };
  return s;
}
console.log(start({ status: "idle" }).status);

Modelowanie zdarzeń

Same zdarzenia również mogą tworzyć unię dyskryminowaną. Każdy typ zdarzenia uruchamia określone przejście.

type Event =
  | { type: "FETCH" }
  | { type: "RESOLVE"; data: string }
  | { type: "REJECT"; message: string };

const e: Event = { type: "RESOLVE", data: "ok" };
console.log(e.type);

Kompletna funkcja przejścia

Połącz unie stanów i zdarzeń w jednym reduktorze. Przełączanie na podstawie obu elementów sprawia, że każde przejście jest jawne i bezpieczne typowo.

type State =
  | { status: "idle" }
  | { status: "loading" }
  | { status: "success"; data: string }
  | { status: "error"; message: string };
type Event =
  | { type: "FETCH" }
  | { type: "RESOLVE"; data: string }
  | { type: "REJECT"; message: string };

function reduce(s: State, e: Event): State {
  if (e.type === "FETCH") return { status: "loading" };
  if (e.type === "RESOLVE") return { status: "success", data: e.data };
  return { status: "error", message: e.message };
}
console.log(reduce({ status: "idle" }, { type: "FETCH" }).status);

Nieprawidłowe stany są niemożliwe do wyrażenia

Nie można jednocześnie mieć data i error message. Konstrukcja unii z założenia uniemożliwia tworzenie sprzecznych stanów.

type State =
  | { status: "success"; data: string }
  | { status: "error"; message: string };

// const bad: State = { status: "success", data: "x", message: "y" };
// Allowed extra props would be flagged in strict object checks.
console.log("no contradictory states");

Ochrona przed nieprawidłowymi przejściami

Można ignorować zdarzenia, które nie mają zastosowania w bieżącym stanie, dzięki czemu maszyna pozostaje spójna zamiast kończyć działanie błędem.

type State = { status: "idle" } | { status: "loading" };
type Event = { type: "FETCH" } | { type: "CANCEL" };

function reduce(s: State, e: Event): State {
  if (s.status === "loading" && e.type === "CANCEL") return { status: "idle" };
  if (s.status === "idle" && e.type === "FETCH") return { status: "loading" };
  return s; // ignore invalid combos
}
console.log(reduce({ status: "loading" }, { type: "CANCEL" }).status);

Dodawanie sprawdzania kompletności

Połącz reduktor z assertNever, aby dodanie nowego stanu lub zdarzenia wskazało każde miejsce wymagające aktualizacji.

function assertNever(x: never): never { throw new Error("unhandled"); }
type State = { status: "idle" } | { status: "loading" } | { status: "done"; data: string };

function view(s: State): string {
  switch (s.status) {
    case "idle": return "idle";
    case "loading": return "loading";
    case "done": return s.data;
    default: return assertNever(s);
  }
}
console.log(view({ status: "done", data: "ok" }));

Stany początkowe i końcowe

Wyznacz wyraźny stan początkowy (często idle) oraz stany końcowe (success lub error). W ten sposób dokumentujesz cykl życia maszyny.

type State =
  | { status: "idle" }
  | { status: "loading" }
  | { status: "success"; data: string }
  | { status: "error"; message: string };

const initial: State = { status: "idle" };
console.log("Start:", initial.status);

Kompletna miniaturowa maszyna stanów

Oto cały przepływ: rozpoczęcie w stanie idle, przejście do loading podczas pobierania i przejście do success po pomyślnym zakończeniu. Typy pilnują poprawności każdego kroku.

type State = { status: "idle" } | { status: "loading" } | { status: "success"; data: string };
type Event = { type: "FETCH" } | { type: "RESOLVE"; data: string };

function reduce(s: State, e: Event): State {
  if (e.type === "FETCH") return { status: "loading" };
  return { status: "success", data: e.data };
}
let st: State = { status: "idle" };
st = reduce(st, { type: "FETCH" });
st = reduce(st, { type: "RESOLVE", data: "hi" });
console.log(st.status, st.status === "success" ? st.data : "");

Szybkie sprawdzenie: maszyny stanów

Sprawdź, czy rozumiesz modelowanie maszyn stanów.

Podsumowanie: modelowanie maszyn stanów

Zamodelowali Państwo stany idle/loading/success/error jako unię dyskryminowaną, napisali bezpieczne typowo przejścia oparte na uniach stanów i zdarzeń oraz użyli sprawdzania kompletności, aby maszyna pozostała poprawna w miarę rozwoju.

type State = { status: "idle" } | { status: "loading" } | { status: "success"; data: string };
const s: State = { status: "success", data: "done" };
console.log(s.status === "success" ? s.data : "");

Często zadawane pytania

Czy lekcja „Modelowanie automatów stanów” jest bezpłatna?

Tak — pełny tekst „Modelowanie automatów stanów” 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 „Modelowanie automatów stanów”?

Reprezentuj skończone stany za pomocą unii rozróżnianych Ć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 4 z 4.

Ile czasu zajmuje lekcja „Modelowanie automatów stanów”?

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. Budowanie unii rozróżnianych
  2. Zawężanie na podstawie właściwości rozróżniającej
  3. Sprawdzanie kompletności za pomocą never
  4. Modelowanie automatów stanów
← Powrót do TypeScript Academy