Menu

TypeScript Literaltypen und as const, mit Beispielen

Ein Literaltyp ist ein Typ mit genau einem Wert, etwa "GET" oder 404. String-, Zahl- und Boolean-Literaltypen, Unions aus Literalen, warum let erweitert und const nicht, was as const bewirkt und const-Typparameter.

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

Ein Literaltyp ist ein Typ mit genau einem Wert: "up" ist ein Typ, dessen einziger Member der String "up" ist, und 404 ist ein Typ, dessen einziger Member die Zahl 404 ist. Allein sind sie nicht sehr nützlich. Zu einer Union verbunden, geben sie dir eine Variable, die eine feste Menge von Werten akzeptiert und sonst nichts.

Ohne den Kommentar @ts-expect-error ist der letzte Aufruf ein Fehler beim Kompilieren (TS2345). Mit ihm kompiliert das Programm, und der Aufruf läuft trotzdem und gibt moving north by 1 aus: Literaltypen existieren nur für den Compiler, und zur Laufzeit ist der Wert ein gewöhnlicher String.

String-, Zahl- und Boolean-Literale

Jeder String, jede Zahl, jeder Bigint und jeder Boolean-Wert lässt sich als Typ schreiben. Der Compiler akzeptiert dann nur genau diesen Wert.

let method: "GET" = "GET";
let code: 404 = 404;
let ok: true = true;
let big: 10n = 10n;

type Port = 80 | 443 | 8080;
const port: Port = 443;

boolean selbst ist nur die Union true | false, deshalb bleibt beim Einengen eines boolean mit if (flag) im else-Zweig false übrig.

LiteraltypErlaubtWeiterer Typ
"GET"nur den String "GET"string
404nur die Zahl 404number
10nnur den Bigint 10bigint
truenur trueboolean

Unions aus Literalen

Der übliche Einsatz ist eine Union, die jeden erlaubten Wert aufführt. In der Funktion engt der Compiler die Union ein, während du sie prüfst, sodass jeder Zweig genau weiß, welchen Wert er hat.

Eine Union aus String-Literalen ist die übliche Alternative zu einem Enum in TypeScript. Sie kostet zur Laufzeit nichts, die Werte sind einfache Strings, die du loggen und per JSON senden kannst, und ein Tippfehler ist ein Compilerfehler. Mehr zu den Abwägungen unter Enums.

Widening: let vs const

Wenn TypeScript einen Typ aus einem Literal ableitet, schaut es, ob sich der Wert ändern kann. Eine const-Variable kann nie neu zugewiesen werden, also behält sie den Literaltyp. Eine let-Variable kann es, also wird ihr Typ zum allgemeinen Typ erweitert.

Fahre im Editor mit der Maus über jeden Namen, um den abgeleiteten Typ zu sehen. Willst du eine let, die nur bestimmte Werte enthält, annotiere sie: let mode: "light" | "dark" = "light".

Warum Objekteigenschaften erweitert werden

Eigenschaften eines Objektliterals sind veränderbar, also werden sie ebenfalls erweitert, selbst wenn das Objekt in einer const liegt. So begegnet man Literaltypen am häufigsten unabsichtlich:

Der Compiler meldet:

index.ts(7,15): error TS2345: Argument of type 'string' is not assignable to parameter of type '"GET" | "POST"'.

req wird als { url: string; method: string } abgeleitet, weil später Code req.method = "DELETE" ausführen könnte. Es gibt drei Lösungen:

Eine vierte Möglichkeit ist satisfies, das das Objekt gegen einen Typ prüft und dabei seine literalen Eigenschaftstypen behält.

as const

as const ist eine Const Assertion. Setze sie hinter einen Ausdruck, und der Compiler leitet den engsten möglichen Typ ab:

  • String, Zahl und Boolean-Werte behalten ihre Literaltypen
  • Objekteigenschaften werden readonly
  • Array-Literale werden zu readonly Tupeln mit fester Länge

Die Assertion gilt nur beim Kompilieren. Das erzeugte JavaScript ist dasselbe Objektliteral ohne as const, also hindert nichts anderen Code daran, es zur Laufzeit zu verändern. Brauchst du eine Garantie zur Laufzeit, rufe zusätzlich Object.freeze auf.

Ein Union-Typ aus einem as const Array

Ein häufiges Muster: Die erlaubten Werte liegen in einem Array, über das du zur Laufzeit iterieren kannst, und der Union-Typ wird daraus abgeleitet. (typeof arr)[number] bedeutet „der Typ eines beliebigen Elements von arr“.

Ohne as const wäre ROLES ein string[] und Role einfach string. Der Cast zu readonly string[] in isRole ist nötig, weil includes auf einem Tupel aus Literalen nur diese Literale akzeptiert, und der Sinn der Funktion ist, einen String zu prüfen, der vielleicht keines ist. Dasselbe Objektmuster funktioniert für Zuordnungen von Schlüsseln zu Werten: const Status = { Active: "active", Banned: "banned" } as const, dann type Status = (typeof Status)[keyof typeof Status].

const-Typparameter

Eine generische Funktion erweitert normalerweise die Literale, die du ihr übergibst. Seit TypeScript 5.0 kannst du einen Typparameter als const markieren, dann leitet der Compiler das Argument ab, als stünde as const daran, ohne dass der Aufrufer es schreiben muss.

Das ist vor allem ein Werkzeug für Bibliotheksautoren: Routendefinitionen, Builder und Schema-Helfer nutzen es, damit Aufrufer aus einfachen Literalen genaue Typen bekommen.

Die Bedeutungen von const

Das Schlüsselwort const taucht in TypeScript-Code an vier verschiedenen Stellen auf:

SyntaxArtWas es tut
const x = 1JavaScript-Deklarationdie Bindung kann nicht neu zugewiesen werden; ein Literalwert behält seinen Literaltyp
expr as constTypeScript-Assertionengster Typ: Literale, readonly Eigenschaften, readonly Tupel
function f<const T>()TypeScript-Typparameterleitet Argumente ab, als stünde as const daran
const enum E {}TypeScript-Enumein Enum, dessen Member beim Kompilieren eingesetzt werden

Keins davon friert ein Objekt zur Laufzeit ein. const obj = { a: 1 } erlaubt weiterhin obj.a = 2; nur obj selbst neu zuzuweisen ist ein Fehler.

Häufig gestellte Fragen

Was ist ein Literaltyp in TypeScript?

Ein Typ, der genau einen Wert erlaubt. "GET" ist ein Typ, dessen einziger Wert der String "GET" ist, 404 ist ein Typ, dessen einziger Wert die Zahl 404 ist, und true ist ein Typ, dessen einziger Wert true ist. Am nützlichsten sind sie in Unions kombiniert, etwa type Method = "GET" | "POST".

Was macht as const in TypeScript?

as const ist eine Const Assertion. Sie sagt dem Compiler, für einen Ausdruck den engsten Typ abzuleiten: String und Zahlenwerte behalten ihre Literaltypen, Objekteigenschaften werden readonly, und Array-Literale werden zu readonly Tupeln. Sie ändert nur den Typ; der Wert zur Laufzeit ist dasselbe einfache Objekt oder Array und wird nicht eingefroren.

Warum leitet TypeScript string statt meines Literals ab?

Weil der Wert veränderbar ist. let x = "a" und die Eigenschaft in { method: "GET" } können später neu zugewiesen werden, also erweitert TypeScript sie zu string. Eine const-Variable behält den Literaltyp "a". Um Literale in einem Objekt zu behalten, annotiere es mit dem Literaltyp, nutze as const oder satisfies.

Was ist der Unterschied zwischen const und as const?

const ist eine JavaScript-Deklaration: Die Variable kann nicht neu zugewiesen werden, aber das Objekt, auf das sie zeigt, lässt sich weiterhin ändern. as const ist eine TypeScript-Typ-Assertion: Sie macht jede Eigenschaft des Werts im Typsystem readonly und literal. Keins von beiden friert das Objekt zur Laufzeit ein; dafür nimmst du Object.freeze.

Wie bekomme ich einen Union-Typ aus einem Array von Strings?

Deklariere das Array mit as const und greife dann per number auf seinen Typ zu: const roles = ["admin", "user"] as const; type Role = (typeof roles)[number]; ergibt "admin" | "user". Ohne as const ist das Array string[], und das Ergebnis ist nur string.

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S