TypeScript-Typzusicherung

Typzusicherung ist ein Mechanismus, der dem Compiler sagt: „Ich kenne den Typ dieses Werts besser als du.“ Sie ermöglicht Entwicklern, die Ergebnisse der Typinferenz von TypeScript manuell zu überschreiben, ähnlich der Typkonvertierung in anderen Sprachen, abersie wirkt sich nur während der Kompilierungsphase aus und erzeugt keinen Laufzeitcode.。


Zwei Syntaxformen

Es gibt zwei Schreibweisen für Typzusicherungen; es wird empfohlen, durchgängig dieasSyntax zu verwenden; die Winkelklammer-Syntax steht im Konflikt mit der Tag-Syntax in JSX-Dateien.

Beispiel

// ① Winkelklammer-Syntax (nicht empfohlen, kann nicht in .tsx-Dateien verwendet werden)
const str1: any = "hello";
const len1: number = (<string>str1).length;

// ② as-Syntax (empfohlen)
const str2: any = "world";
const len2: number = (str2 as string).length;

console.log(len1);  // 5
console.log(len2);  // 5

Ausgabe:

5
5

Hinweis:In React's.tsxDateien, die Winkelklammer-Syntax kollidiert mit JSX-Tags, daher muss dieasSyntax verwendet werden.


Häufige Anwendungsfälle

1. Umgang mit any / unknown-Typen

Daten, die aus externen Schnittstellen, JSON-Parsing und anderen Szenarien stammen, sind normalerweiseany; Assertions können Typ-Hinweise wiederherstellen.

Beispiel

const response: any = { name: "Alice", age: 25 };

// Als bestimmten Typ assertieren, um Typ-Hinweise zu erhalten
const user = response as { name: string; age: number };

console.log(user.name);  // Alice
console.log(user.age);   // 25

Ausgabe:

Alice
25

2. Union-Typen eingrenzen

Wenn Sie den spezifischen Zweig eines Union-Typs kennen, der Compiler ihn aber nicht automatisch bestimmen kann, können Sie eine Assertion verwenden, um den Typ eindeutig anzugeben.

Beispiel

type Shape =
    | { kind: "circle"; radius: number }
    | { kind: "rect"; width: number; height: number };

function getArea(shape: Shape): number {
    if (shape.kind === "circle") {
        return Math.PI * (shape as { kind: "circle"; radius: number }).radius ** 2;
    }
    const rect = shape as { kind: "rect"; width: number; height: number };
    return rect.width * rect.height;
}

console.log(getArea({ kind: "circle", radius: 5 }).toFixed(2));  // 78.54
console.log(getArea({ kind: "rect", width: 4, height: 6 }));     // 24

Ausgabe:

78.54
24

Tipp:Bevorzuge die Verwendung von Type Guards (typeof / instanceof/ diskriminante Eigenschaften) um Typen einzugrenzen; verwende Assertions nur in Szenarien, die Guards nicht abdecken können.

3. DOM-Elemente manipulieren

document.querySelectorDer Rückgabetyp istElement | null; erst nachdem es als spezifischen Elementtyp assertiert wurde, kannst du auf seine exklusiven Eigenschaften zugreifen.

Beispiel

// querySelector gibt Element | null zurück
const input = document.querySelector("#username") as HTMLInputElement;

// Nach der Assertion kannst du auf die exklusiven Eigenschaften von HTMLInputElement zugreifen
// console.log(input.value);

// Sicherer Ansatz: zuerst auf null prüfen, dann assertieren
const btn = document.querySelector("#submit");
if (btn) {
    (btn as HTMLButtonElement).disabled = true;
}

Nicht-Null-Assertion !

Add!nach dem Wert, um dem Compiler mitzuteilen, dass der Wert nichtnulloderundefined; geeignet für Szenarien, in denen Sie sicher sind, dass er nicht null ist, aber der Compiler es nicht ableiten kann.

Beispiel

function printLength(str?: string) {
    // Verwende !, um zu bestätigen, dass str definitiv einen Wert hat
    console.log(str!.length);
}

// Läuft normal
printLength("hello");  // 5

// Laufzeitfehler: Cannot read properties of undefined
// printLength();

Ausgabe:

5

Warnung:Die Non-Null-Assertion umgeht die Nullprüfung des Compilers; wenn der tatsächliche Wert vorliegtnull / undefined, wird zur Laufzeit trotzdem ein Fehler ausgelöst. Wenn die Bedingungen es zulassen, bevorzugen Sie die Verwendung von Optional Chaining?.stattdessen.


Const-Assertion as const

as constLeitet Literale als die engsten readonly-Literaltypen ab, häufig verwendet zum Definieren von Enum-Werten, Konfigurationskonstanten und Tupeln.

Beispiel

// Normale Deklaration: als string[] abgeleitet, Elemente sind modifizierbar
const colors1 = ["red", "green", "blue"];
colors1.push("yellow");  // Erlaubt

// as const: als readonly ["red", "green", "blue"] abgeleitet; sowohl Elemente als auch Länge sind unveränderlich
const colors2 = ["red", "green", "blue"] as const;
// colors2.push("yellow"); // Fehler: Kann nicht auf ein schreibgeschütztes Array pushen

// Dasselbe gilt für Objekte: Alle Eigenschaften werden zu readonly-Literaltypen
const config = {
    host: "localhost",
    port: 3000
} as const;
// config.port = 8080; // Fehler: readonly-Eigenschaft kann nicht geändert werden

console.log(colors2);         // ['red', 'green', 'blue']
console.log(config.host);     // localhost
console.log(config.port);     // 3000

Ausgabe:

['red', 'green', 'blue']
localhost
3000

Typzusicherung ist keine Typkonvertierung

Eine Typzusicherung wirkt sich nur auf die Typprüfung des Compilers aus und erzeugt nach der Kompilierung keinen Konvertierungscode. Beim Zusichern"42"asnumber, zur Laufzeit ist es immer noch ein String.

Beispiel

const strNum: any = "42";

// Als number zugesichert, aber zur Laufzeit ist es immer noch ein String
const wrongNum = strNum as number;
console.log(typeof wrongNum);    // string (keine Zahl!)
console.log(wrongNum + 1);       // 421 (String-Verkettung, keine numerische Addition)

// Echte Typkonvertierung erfordert Konvertierungsfunktionen
const realNum = Number(strNum);
console.log(typeof realNum);     // number
console.log(realNum + 1);        // 43

Ausgabe:

string
421
number
43

Doppelte Assertion

Wenn es keine Überlappung zwischen zwei Typen gibt, verweigert TypeScript eine direkte Assertion. In diesem Fall kannst duunknownals Zwischenstufe verwenden, aber dies ist eine gefährliche Operation und sollte nach Möglichkeit vermieden werden.

Beispiel

const num = 42;

// Direkte Assertion: number und string überschneiden sich nicht, der Compiler meldet einen Fehler
// const str = num as string;

// Doppelte Assertion: zuerst als unknown assertieren, dann als Zieltyp assertieren
const str = num as unknown as string;

console.log(str);          // 42
console.log(typeof str);   // number (Laufzeittyp unverändert; Assertion wirkt nur zur Kompilierzeit)

Ausgabe:

42
number

Warnung:Die doppelte Assertion umgeht das Typsystem von TypeScript vollständig und kann leicht Laufzeitfehler verursachen. Verwende sie nur in Sonderfällen wie ungenauen Typen in Drittanbieter-Bibliotheken und vermerke den Grund im Code.


Vergleich der Assertion-Methoden

Assertion-Methode Syntax Typisches Szenario Risiko
as-Assertionvalue as TypeUmwandlung von any in einen bestimmten Typ, DOM-OperationenNiedrig (Überlappungsprüfung vorhanden)
Non-Null-Assertionvalue!Bestätigung von non-null/undefinedMittel (überspringt Nullprüfung)
Const-Assertionvalue as constLiteral-Konstanten, Enum-WerteKeine
Doppelte Assertionvalue as unknown as TErzwungene Konvertierung, wenn Typen keine Überlappung habenHoch (umgeht Prüfungen vollständig)

Zusammenfassung

  • Syntaxauswahl:Verwenden Sie durchgängig dieasSyntax und vermeiden Sie die Winkelklammer-Syntax in JSX
  • Assertion vs. Konvertierung:Assertion wirkt sich nur auf Compile-Time-Typen aus und erzeugt keinen Laufzeitcode; echte Wertkonvertierung erfordert die Verwendung vonNumber()、String()und anderen ähnlichen Funktionen
  • Non-Null-Assertion:Bevor Sie es verwenden!, stellen Sie sicher, dass der Wert wirklich nicht null ist; andernfalls tritt zur Laufzeit ein Fehler auf. Wenn die Bedingungen es zulassen, verwenden Sie vorzugsweise?.
  • Const-Assertion:as constist eine sichere und praktische Assertion, empfohlen für Konfigurationsobjekte und konstante Arrays
  • Doppelte Assertion:ist das letzte Mittel; man muss den Grund kommentieren, wenn man sie verwendet

Weitere verwandte Inhalte