Menu

TypeScript as: Type Assertions und Casting erklärt

Das Schlüsselwort as sagt TypeScript, einen Wert als anderen Typ zu behandeln. Es ist kein Cast: Zur Laufzeit wird nichts umgewandelt oder geprüft. Die Syntax mit as und spitzen Klammern, was der Compiler erlaubt, doppelte Assertions über unknown und wann ein Type Guard das bessere Werkzeug ist.

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

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 willstSchreibeWirkung zur Laufzeit
Dem Compiler einen Typ mitteilen, den du kennstx as Tkeine
Einen String in eine Zahl umwandelnNumber(x), parseInt(x, 10)wandelt um
Alles in einen String umwandelnString(x), `${x}`wandelt um
Zuerst den Typ prüfenein Type Guard, typeof, instanceofprü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:

WerkzeugPrüft beim KompilierenPrüft zur LaufzeitVerwenden, wenn
Annotation const x: T = ...ja, vollständigneindu den Wert selbst baust
satisfies Tja, vollständig, behält den abgeleiteten TypneinObjektliterale, Konfiguration
as Tnur, ob sich die Typen überschneidenneindu mehr weißt als der Compiler
x!entfernt nur null / undefinedneindu weißt, dass ein Wert gesetzt ist
Type Guard x is Tder Rumpf des Guards ist gewöhnlicher CodejaDaten 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.

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S