Menu

TypeScript switch case: Narrowing und vollständige Prüfung

Die switch-Anweisung in TypeScript: Syntax, wie jeder case einen Union-Typ einengt, vollständige switches, die nicht kompilieren, wenn ein Fall fehlt, das Muster switch (true), Fallthrough und Block-Scope.

Diese Seite enthält ausführbare Editoren - bearbeiten, ausführen und Ausgabe sofort sehen.

Eine switch-Anweisung in TypeScript ist das switch von JavaScript mit Typprüfung. Sie vergleicht einen Wert mit === gegen jeden case, führt den passenden Zweig aus und hört bei break oder return auf. TypeScript engt den geprüften Wert in jedem case ein und kann prüfen, dass jeder mögliche Wert behandelt wird.

Gestapelte Labels (case "sat": case "sun":) teilen sich einen Zweig. return beendet die Funktion, danach ist also kein break nötig.

Syntax

switch (expression) {
    case value1:
        // runs when expression === value1
        break;
    case value2:
    case value3:
        // runs for value2 or value3
        break;
    default:
        // runs when nothing else matched
}
  • Der Vergleich nutzt strikte Gleichheit, ===: case 1 passt nicht auf den String "1".
  • Ohne break, return oder throw läuft die Ausführung in den nächsten case weiter (Fallthrough).
  • default ist optional und kann überall stehen, üblich ist aber am Ende.
  • Ein case-Wert, von dem TypeScript beweisen kann, dass er nie passt, ist der Fehler TS2678. Bei einem Parameter vom Typ "a" | "b" meldet case "c": den Text Type '"c"' is not comparable to type '"a" | "b"'., was Tippfehler in case-Labels abfängt.

Narrowing in jedem case

In jedem case weiß TypeScript, welcher Wert gepasst hat, und engt den Typ ein. Am nützlichsten ist das bei einer Discriminated Union: Du prüfst im switch die gemeinsame Tag-Eigenschaft, und jeder case sieht die passende Variante mit ihren eigenen Eigenschaften.

shape.radius kompiliert nur im case "circle". Außerhalb davon könnte shape ein Rechteck sein, das kein radius hat. Es gibt kein default, und die Funktion besteht trotzdem die Typprüfung mit Rückgabetyp number, weil TypeScript sieht, dass die drei cases jede kind abdecken. Weitere Muster darauf aufbauend stehen auf der Seite zu Discriminated Unions.

Vollständiger switch mit never

Die Funktion oben kompiliert nicht mehr, wenn eine vierte Form ohne case hinzukommt (TS2366, ein fehlendes return). Das funktioniert nur, wenn die Funktion einen Wert zurückgibt. Für eine Garantie, die auch in void-Code greift und eine klarere Meldung liefert, fügst du ein default hinzu, das den Wert never zuweist:

index.ts(14,19): error TS2322: Type '{ kind: "triangle"; base: number; height: number; }' is not assignable to type 'never'.

Nach den behandelten cases bleibt für shape nur noch die Dreiecksvariante übrig, und die lässt sich never nicht zuweisen. Der Fehler nennt genau, was fehlt. Ergänze case "triangle": return (shape.base * shape.height) / 2;, dann sieht das default den Typ never, und der Block kompiliert und gibt 9 aus. Das throw schützt zur Laufzeit weiterhin vor fehlerhaften Daten, etwa einer kind aus JSON, die die Typen nicht vorhergesehen haben.

Viele Codebasen verpacken die Prüfung in eine Hilfsfunktion:

Dieselbe Technik funktioniert mit Enums: Prüfe im switch den Enum-Wert und übergib ihn im default an assertNever.

switch (true) für Bereiche und Bedingungen

switch vergleicht Werte, Bereiche brauchen also einen Trick: Prüfe auf true und schreibe in jeden case eine Bedingung. Seit TypeScript 5.3 engen diese Bedingungen Typen genauso ein wie if-Anweisungen.

Die cases werden der Reihe nach geprüft, also kommt der spezifischste zuerst. Ob das besser lesbar ist als if / else if, ist Geschmackssache; das Verhalten ist dasselbe.

Fallthrough und break

Ein case mit Code, aber ohne break, return oder throw fällt in den nächsten case durch. Das ist fast immer ein Fehler. Die Compileroption noFallthroughCasesInSwitch (nicht Teil von strict) macht daraus den Fehler TS7029, Fallthrough case in switch., erlaubt aber weiterhin gestapelte leere Labels.

Absichtlicher Fallthrough wie dieser funktioniert, muss mit aktivem noFallthroughCasesInSwitch aber umgeschrieben werden, zum Beispiel mit getrennten if-Prüfungen. Das ist meist ohnehin klarer.

Variablen in cases

Der gesamte Rumpf von switch ist ein Block, eine in einem case deklarierte const ist also in den anderen sichtbar (und eine erneute Deklaration ist ein Fehler). Setze einen case in geschweifte Klammern, um ihm einen eigenen Scope zu geben:

Ohne die Klammern ist das zweite const unit der Compilerfehler TS2451, Cannot redeclare block-scoped variable 'unit'.

switch vs Objekt-Lookup

Wenn jeder case nur einen Wert auf einen anderen abbildet, ist ein mit Record typisiertes Objekt kürzer, und TypeScript prüft, dass jeder Schlüssel vorhanden ist:

Einen Schlüssel wegzulassen ist ein Compilerfehler, was dieselbe Vollständigkeit wie eine never-Prüfung ergibt. Behalte switch für Fälle, die unterschiedliche Logik ausführen, Union-Varianten einengen oder früh zurückkehren.

Häufig gestellte Fragen

Wie schreibt man eine switch-Anweisung in TypeScript?

Genau wie in JavaScript: switch (value) { case "a": ...; break; default: ... }. Cases werden mit === verglichen. TypeScript ergänzt Prüfungen: Ein case-Wert, der nie zum geprüften Typ passen kann, ist ein Fehler (TS2678), und in jedem case ist die geprüfte Variable auf diesen Fall eingeengt.

Wie mache ich einen switch in TypeScript vollständig (exhaustive)?

Füge ein default hinzu, das den Wert einer Variablen vom Typ never zuweist: default: { const unreachable: never = value; throw new Error(...) }. Wird jeder Member der Union behandelt, ist der Wert dort never, und es kompiliert. Fehlt einer, meldet der Compiler den fehlenden Member (TS2322).

Wie behandle ich in einem TypeScript-switch mehrere Fälle mit demselben Code?

Setze die Labels ohne Code dazwischen untereinander: case "sat": case "sun": return "weekend";. Leere Cases fallen zum nächsten durch. Die Option noFallthroughCasesInSwitch meldet nur Cases, die Code, aber kein break oder return haben, gestapelte Labels bleiben also erlaubt.

Engt switch (true) in TypeScript Typen ein?

Ja, seit TypeScript 5.3. In switch (true) { case typeof x === "string": ... } ist x in diesem case auf string eingeengt, genau wie in einem if. Es ist eine gut lesbare Alternative zu einer Kette aus if/else if mit Bereichs- oder Typprüfungen.

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S