value as Type ist eine Typ-Assertion: Sie sagt TypeScript, value als Type zu behandeln. Man nennt das oft Cast, aber es ist nur eine Anweisung an den Compiler. Sie wird aus der JavaScript-Ausgabe entfernt, wandelt nichts um und prüft zur Laufzeit nichts.
Das ist der typische Einsatz: Du weißt über einen Wert mehr als der Compiler (hier die Form von JSON-Daten) und sagst es ihm. Liegst du falsch, warnt dich nichts. Die nächsten Abschnitte zeigen, was das bedeutet und wann eine Prüfung zur Laufzeit die bessere Wahl ist.
as und die Syntax mit spitzen Klammern
Es gibt zwei Schreibweisen derselben Assertion:
const someValue: unknown = "hello";
const a = someValue as string; // as syntax
const b = <string>someValue; // angle-bracket syntax, same meaning
Die Form mit spitzen Klammern ist in .tsx-Dateien nicht erlaubt, wo <string> als JSX-Tag gelesen würde. Nimm überall as, dann stellt sich die Frage nie. Assertions binden schwach, setze sie also in Klammern, wenn der Ausdruck weitergeht: (value as string).length.
Assertions wandeln keine Werte um
Genau das verursacht echte Bugs. Eine Assertion ändert, was der Compiler über einen Wert glaubt, nicht den Wert selbst:
Der Compiler glaubt, asserted sei eine number, also besteht asserted + 1 die Typprüfung als Rechnung. Zur Laufzeit ist es weiterhin der String "42", und JavaScript verkettet. Um den Typ eines Werts zu ändern, wandle ihn um: Number(x), String(x), Boolean(x), BigInt(x), new Date(x). Die Seite String in Zahl umwandeln vergleicht die Umwandlungsfunktionen.
| Du willst | Schreibe | Wirkung zur Laufzeit |
|---|---|---|
| Dem Compiler einen Typ mitteilen, den du kennst | x as T | keine |
| Einen String in eine Zahl umwandeln | Number(x), parseInt(x, 10) | wandelt um |
| Alles in einen String umwandeln | String(x), `${x}` | wandelt um |
| Zuerst den Typ prüfen | ein Type Guard, typeof, instanceof | prüft |
Was der Compiler erlaubt
as ist nicht unbegrenzt. TypeScript erlaubt x as T, wenn einer der Typen dem anderen zuweisbar ist: Erweitern ("a" as string, dog as Animal) und Einengen (animal as Dog, unknown as User) sind beide in Ordnung. Überschneiden sich die Typen gar nicht, verweigert es:
Der Compiler meldet index.ts(3,11): error TS2352: Conversion of type 'string' to type 'number' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. Die Meldung nennt selbst den Notausgang: input as unknown as number. Diese doppelte Assertion kompiliert und ist zur Laufzeit genauso falsch wie das Beispiel oben. Wenn du sie zu brauchen glaubst, ist die richtige Lösung meist eine Umwandlung (Number(input)) oder ein anderer Typ.
Die Regel zur Überschneidung ist bei Objekten locker. Ein Objektliteral, das einige der Eigenschaften hat, wird akzeptiert, und so lässt as still unvollständige Objekte durch:
Eine Annotation (const draft: User = { name: "Ada" }) oder satisfies User würde das fehlende email melden (TS2741). Nimm as bei einem Objektliteral nur, wenn du es wirklich später füllen willst, und baue lieber das vollständige Objekt.
as const ist etwas anderes
as const sieht aus wie eine Assertion, bewirkt aber das Gegenteil von Lockern: Es macht ein Literal so eng wie möglich. Strings bleiben Literaltypen, Arrays werden zu readonly Tupeln, und Objekteigenschaften werden readonly.
Das ist sicher, weil es das Literal genau beschreibt, statt etwas zu behaupten, was der Compiler nicht sehen kann. (Das sizes as readonly string[] in isSize ist eine erweiternde Assertion und ebenfalls sicher: Sie lässt includes jeden String akzeptieren.) Mehr dazu unter Literaltypen.
Wann ein Type Guard das bessere Werkzeug ist
as ist eine Behauptung; ein Type Guard ist eine Prüfung. An einer Grenze, an der Daten von außerhalb deines Codes kommen (JSON, fetch, localStorage, Benutzereingaben, eine Nachricht), kann die Behauptung falsch sein, und eine Assertion macht aus einem klaren Fehler an der Grenze einen verwirrenden an ganz anderer Stelle.
Eine grobe Orientierung zu den ähnlich aussehenden Werkzeugen:
| Werkzeug | Prüft beim Kompilieren | Prüft zur Laufzeit | Verwenden, wenn |
|---|---|---|---|
Annotation const x: T = ... | ja, vollständig | nein | du den Wert selbst baust |
satisfies T | ja, vollständig, behält den abgeleiteten Typ | nein | Objektliterale, Konfiguration |
as T | nur, ob sich die Typen überschneiden | nein | du mehr weißt als der Compiler |
x! | entfernt nur null / undefined | nein | du weißt, dass ein Wert gesetzt ist |
Type Guard x is T | der Rumpf des Guards ist gewöhnlicher Code | ja | Daten von außen |
Zwei gute Einsätze von as bleiben: etwas einengen, dem der Compiler nicht folgen kann (ein Map-Eintrag, den du zwei Zeilen vorher gesetzt hast, ein Wert aus einer untypisierten Bibliothek), und Testcode, der unvollständige Fixtures baut. Halte sie klein und nah an der Stelle, an der du weißt, dass die Behauptung stimmt.
Häufig gestellte Fragen
Was macht as in TypeScript?
value as Type ist eine Typ-Assertion: Sie sagt dem Compiler, value ab hier als Type zu behandeln. Sie wird aus dem kompilierten JavaScript entfernt, wandelt also nichts um und prüft zur Laufzeit nichts. Ist die Assertion falsch, scheitert das Programm später, dort, wo der falsche Typ verwendet wird.
Wie caste ich in TypeScript einen Typ?
TypeScript hat keine Casts zur Laufzeit. Nimm as (oder das ältere <Type>value), um den statischen Typ zu ändern, wenn du mehr weißt als der Compiler. Um einen Wert tatsächlich umzuwandeln, rufst du eine Funktion auf: Number("42"), String(42), Boolean(x), new Date(text).
Was bedeutet "as unknown as" in TypeScript?
Eine doppelte Assertion. TypeScript verweigert x as T, wenn sich die beiden Typen überhaupt nicht überschneiden (Fehler TS2352), und der Umweg über unknown umgeht diese Prüfung, weil man alles zu unknown und von unknown aus asserten kann. Das schaltet die Typprüfung für diesen Wert komplett ab, reserviere es also für Tests und für Code, in dem du den Typ auf anderem Weg geprüft hast.
Was ist der Unterschied zwischen as und spitzen Klammern in TypeScript?
In der Bedeutung keiner: <string>value und value as string sind dieselbe Assertion. Die Form mit spitzen Klammern ist in .tsx-Dateien nicht nutzbar, weil sie mit JSX kollidiert, deshalb verwendet jeder as.
Was ist der Unterschied zwischen as und satisfies?
as überschreibt den abgeleiteten Typ und prüft sehr wenig (fehlende Eigenschaften sind erlaubt). satisfies prüft den Wert gegen einen Typ, meldet fehlende oder zusätzliche Eigenschaften und behält den genauen abgeleiteten Typ. Bevorzuge satisfies für Objektliterale und as nur, wenn du wirklich mehr weißt als der Compiler.