Le sac de champs optionnels laisse construire des états qui ne devraient pas exister.The bag of optional fields lets you build states that shouldn't exist.
Un seul objet, un booléen et deux champs optionnels : et voilà l'état « en chargement, réussi, et en erreur » à la fois — parfaitement constructible, parfaitement absurde. On le « gère » alors à coups de if éparpillés, en priant pour avoir couvert toutes les combinaisons. La discriminated union pose la question à l'envers : et si cet état illégal ne se construisait même plus ?A single object, one boolean and two optional fields: and there it is, the 'loading, succeeded, and errored' state all at once — perfectly buildable, perfectly absurd. So you 'handle' it with scattered ifs, praying you covered every combination. The discriminated union flips the question: what if that illegal state could no longer be built at all?
type RequestState = { loading: boolean; data?: User; error?: string; }; // rien n'interdit l'état absurde : const s: RequestState = { loading: true, data: user, error: "boom" }; // en cours ? réussi ? échoué ? les trois à la fois — et ça compile.
Le sac multiplie les combinaisons ; cinq sur huit n'ont aucun sens, et c'est à toi de les refuser à l'exécution. L'union ne décrit que les trois formes réelles — le reste devient impossible à écrire.The bag multiplies combinations; five out of eight make no sense, and it's on you to reject them at runtime. The union describes only the three real shapes — the rest becomes impossible to write.
type RequestState = | { status: "loading" } | { status: "success"; data: User } | { status: "error"; error: string }; // l'état absurde ne se construit même plus : const s: RequestState = { status: "loading", data: user }; // ✗ 'data' n'existe pas sur la branche "loading" — refusé à la compilation
« Cet état que je vérifie partout — puis-je le rendre impossible à construire ? » Si deux champs ne devraient jamais coexister, ne les mets pas dans le même objet : mets-les dans des branches exclusives, séparées par un discriminant."This state I check everywhere — can I make it impossible to build?" If two fields should never coexist, don't put them in the same object: put them in exclusive branches, split by a discriminant.
Le Vol 2 apprenait à reconstruire une preuve à l'exécution, après coup. Le Vol 3 prend le problème en amont : concevoir des types où l'état invalide ne se construit pas. L'union discriminée en est la brique de base — et le narrowing du Vol 2 devient sa clé de lecture.Vol 2 taught how to rebuild a proof at runtime, after the fact. Vol 3 takes the problem upstream: designing types where the invalid state can't be built. The discriminated union is its basic brick — and Vol 2's narrowing becomes the key to reading it.