Zustände modellieren, statt Booleans zu sammeln.

Lädt noch, schon leer oder doch fehlgeschlagen? Mit klaren TypeScript-Typen wird aus widersprüchlichen Flags ein lesbarer Ablauf.

Beispielartikel aus der CodeKapitel-Konzeptvorschau.

Lesemodus

Vier Flags, viele offene Fragen

Eine Suchansicht beginnt oft mit wenigen Variablen: isLoading, hasError und einer Ergebnisliste. Später kommt hasSearched dazu. Beim Rendern müssen wir nun herausfinden, welche Kombination gerade gemeint ist. Was bedeutet ein Fehler zusammen mit einer gefüllten Liste? Darf eine noch nicht gestartete Suche bereits leer sein? Die Variablen beantworten diese Fragen nicht von selbst.

Das Problem ist nicht der Datentyp Boolean. Es ist die fehlende Verbindung zwischen Informationen, die gemeinsam eine Situation beschreiben. Für eine einfache Suche können wir zunächst vier Situationen festlegen: noch nicht gesucht, Anfrage läuft, Ergebnis vorhanden und Anfrage fehlgeschlagen. Eine leere Ergebnisliste ist dabei ein erfolgreiches Ergebnis. Sie braucht einen passenden Text, aber keinen Fehlerzustand.

Diese Unterscheidung hilft auch beim Gespräch im Team. Statt abstrakt über mehrere Flags zu sprechen, können wir einzelne Bildschirmzustände durchgehen. Für jeden Zustand lässt sich ein konkretes Beispiel festhalten. Das schafft eine gemeinsame Grundlage für Gestaltung, Implementierung und spätere Prüfungen, ohne dass alle Beteiligten zuerst den vorhandenen Code verstehen müssen.

Der Zustand trägt seine Daten

Eine Union macht die vorgesehenen Fälle sichtbar. Jeder Fall bekommt ein gemeinsames Unterscheidungsmerkmal. Daten stehen nur dort zur Verfügung, wo sie sinnvoll sind: Ergebnisse im Erfolgsfall und eine Erklärung im Fehlerfall. Beim Prüfen von status kann TypeScript den Typ entsprechend eingrenzen.

Dadurch lassen sich viele versehentlich widersprüchliche Kombinationen bereits beim Schreiben erkennen. Das ersetzt keine Validierung von Serverantworten und keine Laufzeittests. Es hilft uns aber, innerhalb des Programms mit einem verständlichen Modell weiterzuarbeiten. Die Darstellung kann die Fälle einzeln behandeln, statt mehrere lose Flags zusammenzurechnen.

type Result = { id: string; title: string };

type SearchState =
  | { status: "idle" }
  | { status: "loading" }
  | { status: "success"; results: Result[] }
  | { status: "error"; message: string };

function resultCount(state: SearchState): number | null {
  if (state.status !== "success") return null;
  return state.results.length;
}

Das Modell folgt der Oberfläche

Vielleicht soll die Suche später alte Ergebnisse anzeigen, während eine neue Anfrage läuft. Dann reicht unser erstes Modell nicht mehr. Wir können einen eigenen Aktualisierungszustand einführen, der die bisherigen Ergebnisse enthält. Die zusätzliche Komplexität entsteht dann aus einem gewünschten Verhalten und lässt sich daran erklären.

Auch schnelle aufeinanderfolgende Suchanfragen brauchen eine bewusste Entscheidung. Eine Union verhindert nicht automatisch, dass eine ältere Antwort eine neuere überschreibt. Dafür muss die Anwendung beispielsweise veraltete Antworten erkennen und ignorieren. Typen beschreiben erlaubte Zustände; die Übergänge und ihre Nebenbedingungen müssen wir weiterhin implementieren.

Schreibe beim nächsten Formular oder Datenabruf zuerst die Situationen aus Sicht der lesenden Person auf. Welche Information braucht sie in jedem Fall? Welche Aktion ist möglich? Erst danach übersetzt du diese Situationen in Typen. Ein gutes Zustandsmodell macht die Oberfläche und den Code gleichzeitig verständlicher, weil beide dieselben fachlichen Unterschiede ausdrücken.

Gedanke mitnehmen. Weiterdenken.

Ein gutes Kapitel ist erst der Anfang.

Entdecke weitere Perspektiven auf Software, Architektur und die Arbeit am Code.

Weitere Artikel entdecken