Modellare macchine a stati
Rappresenti stati finiti con union discriminate.
Modellare macchine a stati è una lezione TypeScript Academy gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento TypeScript Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso TypeScript Academy include 4 lezioni in totale.
Gli stati come unione discriminata
I flussi dell'interfaccia utente e asincroni hanno stati distinti: inattivo, caricamento, successo, errore. Modellarli come un'unione discriminata fa sì che ogni stato contenga esattamente i dati di cui ha bisogno.
type State =
| { status: "idle" }
| { status: "loading" }
| { status: "success"; data: string }
| { status: "error"; message: string };
const s: State = { status: "idle" };
console.log(s.status);Payload per ogni stato
Solo lo stato success ha data; solo lo stato error ha message. Gli stati idle e loading non contengono dati aggiuntivi, impedendo così che dati obsoleti passino da uno stato all'altro.
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);Eseguire il rendering di ogni stato
Una funzione che esegue uno switch su status può produrre l'output corretto per ogni stato, rendendo disponibili i campi dei membri solo dove esistono.
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" }));Definire le transizioni
Una macchina a stati passa da uno stato all'altro tramite transizioni. Una funzione di transizione riceve lo stato corrente e un evento e restituisce lo stato successivo.
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);Modellare anche gli eventi
Anche gli eventi possono essere modellati come un'unione discriminata. Ogni tipo di evento attiva una transizione specifica.
type Event =
| { type: "FETCH" }
| { type: "RESOLVE"; data: string }
| { type: "REJECT"; message: string };
const e: Event = { type: "RESOLVE", data: "ok" };
console.log(e.type);Una funzione di transizione completa
Combini le unioni degli stati e degli eventi in un unico reducer. Eseguire lo switch su entrambi rende esplicita e type-safe ogni transizione.
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);Gli stati non validi sono impossibili da rappresentare
Non è possibile avere data e un error message contemporaneamente. La progettazione dell'unione vieta per costruzione gli stati contraddittori.
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");Proteggere dalle transizioni non valide
È possibile ignorare gli eventi che non si applicano allo stato corrente, mantenendo la macchina in uno stato coerente invece di causare un errore.
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);Aggiungere il controllo di esaustività
Abbini il reducer a assertNever affinché l'aggiunta di un nuovo stato o evento evidenzi ogni punto da aggiornare.
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" }));Stati iniziali e finali
Definisca uno stato iniziale chiaro (spesso idle) e gli stati terminali (success o error). In questo modo documenta il ciclo di vita della macchina.
type State =
| { status: "idle" }
| { status: "loading" }
| { status: "success"; data: string }
| { status: "error"; message: string };
const initial: State = { status: "idle" };
console.log("Start:", initial.status);Una piccola macchina a stati completa
Ecco il ciclo completo: si inizia da idle, si passa a loading durante il recupero e si arriva a success al termine. I tipi mantengono coerente ogni passaggio.
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 : "");Verifica rapida: macchine a stati
Verifichi la sua comprensione della modellazione delle macchine a stati.
Riepilogo: modellare macchine a stati
Ha modellato idle/loading/success/error come un'unione discriminata, ha scritto transizioni type-safe sulle unioni di stati ed eventi e ha utilizzato il controllo di esaustività per mantenere corretta la macchina mentre cresce.
type State = { status: "idle" } | { status: "loading" } | { status: "success"; data: string };
const s: State = { status: "success", data: "done" };
console.log(s.status === "success" ? s.data : "");Domande Frequenti
La lezione «Modellare macchine a stati» è gratuita?
Sì — il testo completo di «Modellare macchine a stati» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso TypeScript Academy, passa a CoddyKit PRO. Il corso TypeScript Academy include 4 lezioni in totale.
Cosa imparerò in «Modellare macchine a stati»?
Rappresenti stati finiti con union discriminate. Eserciti TypeScript Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare TypeScript Academy?
Non è richiesta alcuna esperienza precedente. TypeScript Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.
Quanto tempo richiede la lezione «Modellare macchine a stati»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione TypeScript Academy?
Sì. Ogni lezione TypeScript Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Costruire union discriminate
- Restringimento tramite discriminante
- Controllo di esaustività con never
- Modellare macchine a stati