TypeScript Academy · Lektion

Modellering af tilstandsmaskiner

Repræsentér endelige tilstande med diskriminerede unioner

Lektion 4 af 413 trin

Modellering af tilstandsmaskiner er en gratis TypeScript Academy-lektion på CoddyKit. Dette er lektion 4 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i TypeScript Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. TypeScript Academy-kurset indeholder 4 lektioner i alt.

Tilstande som en diskrimineret union

Brugergrænseflader og asynkrone forløb har forskellige tilstande: inaktiv, indlæser, succes og fejl. Ved at modellere dem som en diskrimineret union får hver tilstand præcis de data, den har brug for.

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

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

Data for hver tilstand

Kun tilstanden success har data; kun error har en message. Inaktiv og indlæsning indeholder ingen ekstra data, hvilket forhindrer, at forældede data lækker mellem tilstandene.

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);

Gengivelse af hver tilstand

En funktion, der skifter ud fra status, kan gengive det rigtige resultat for hver tilstand, og medlemsfelterne er kun tilgængelige, hvor de findes.

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" }));

Definition af overgange

En tilstandsmaskine bevæger sig mellem tilstande via overgange. En overgangsfunktion modtager den aktuelle tilstand og en hændelse og returnerer den næste tilstand.

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);

Modellering af hændelser

Hændelser kan også være en diskrimineret union. Hver hændelsestype udløser en bestemt overgang.

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

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

En komplet overgangsfunktion

Kombinér unionerne for tilstande og hændelser i én reducer. Ved at skifte ud fra begge dele bliver hver overgang tydelig og typesikker.

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);

Ulovlige tilstande kan ikke repræsenteres

Du kan ikke have data og en error message på samme tid. Unionens udformning forbyder modstridende tilstande fra starten.

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");

Beskyttelse mod ugyldige overgange

Du kan ignorere hændelser, der ikke gælder for den aktuelle tilstand, så maskinen forbliver i en konsistent tilstand i stedet for at gå ned.

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);

Tilføjelse af fuldstændighedskontrol

Kombinér reduceren med assertNever, så tilføjelsen af en ny tilstand eller hændelse viser alle de steder, du skal opdatere.

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" }));

Indledende og afsluttende tilstande

Angiv en tydelig starttilstand (ofte idle) og afsluttende tilstande (success eller error). Det dokumenterer maskinens livscyklus.

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

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

En komplet lille tilstandsmaskine

Her er hele forløbet: start inaktiv, hent data for at gå til indlæsning, og gå videre til succes, når resultatet foreligger. Typerne sikrer, at hvert trin er korrekt.

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 : "");

Hurtig kontrol: tilstandsmaskiner

Afprøv din forståelse af modellering af tilstandsmaskiner.

Opsamling: modellering af tilstandsmaskiner

Du har modelleret inaktiv, indlæsning, succes og fejl som en diskrimineret union, skrevet typesikre overgange over unioner af tilstande og hændelser og brugt fuldstændighedskontrol til at holde maskinen korrekt, efterhånden som den vokser.

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

Lær TypeScript med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
101
Lektioner
352

Ofte stillede spørgsmål

Er lektionen “Modellering af tilstandsmaskiner” gratis?

Ja — hele teksten til “Modellering af tilstandsmaskiner” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af TypeScript Academy-kurset, skal du opgradere til CoddyKit PRO. TypeScript Academy-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “Modellering af tilstandsmaskiner”?

Repræsentér endelige tilstande med diskriminerede unioner Du øver dig i TypeScript Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på TypeScript Academy?

Der kræves ingen tidligere erfaring. TypeScript Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 4 af 4.

Hvor lang tid tager lektionen “Modellering af tilstandsmaskiner”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

Kan jeg skrive og køre kode i denne TypeScript Academy-lektion?

Ja. Alle TypeScript Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. Opbygning af diskriminerede unioner
  2. Indsnævring på discriminanten
  3. Exhaustiveness-tjek med never
  4. Modellering af tilstandsmaskiner
← Tilbage til TypeScript Academy