Lektionen des Moduls (2/2)
Unions und Type Narrowing
In der Praxis haben Variablen und API-Antworten nicht immer einen einzigen festen Typ. TypeScript bietet Union-Typen (Union Types) zur Verwaltung dieser Variabilität und das Einschränken von Typen (Type Narrowing), um zur Laufzeit sicher mit ihnen zu arbeiten.
Union-Typen (Union Types)
Ein Union-Typ erlaubt es einer Variablen, Werte verschiedener Typen zu akzeptieren. Er wird durch das vertikale Strichsymbol (|) ausgedrückt:
let result: number | string;
result = 42; // Valido
result = 'Errore 404'; // ValidoWenn wir jedoch mit einem Union-Typ arbeiten, können wir Methoden, die nur zu einem der Typen gehören, nicht direkt aufrufen (z. B. können wir .toUpperCase() nicht ausführen, wenn die Variable auch eine number sein kann). Wir müssen zuerst den Typ einschränken.
Einschränken von Typen (Type Narrowing)
Unter Type Narrowing versteht man den Prozess, bei dem TypeScript Kontrollflussstrukturen (wie if oder switch) analysiert, um zur Laufzeit auf einen spezifischeren Typ für eine Variable zu schließen.
Es gibt verschiedene Möglichkeiten, das Einschränken durchzuführen:
1. Der Operator typeof
Ideal zur Unterscheidung primitiver Typen:
function printLength(value: string | number) {
if (typeof value === 'string') {
// Qui TypeScript sa che 'value' è una stringa
console.log(value.length);
} else {
// Qui TypeScript sa che 'value' è un numero
console.log(value.toFixed(2));
}
}2. Der Operator in
Wird verwendet, um das Vorhandensein einer bestimmten Eigenschaft in einem Objekt zu überprüfen:
interface Fish {
swim: () => void;
}
interface Bird {
fly: () => void;
}
function move(animal: Fish | Bird) {
if ('swim' in animal) {
animal.swim(); // Narrowing a Fish
} else {
animal.fly(); // Narrowing a Bird
}
}Diskriminierte Unions (Discriminated Unions)
Das Muster der diskriminierten Unions besteht darin, Objekte zu erstellen, die eine gemeinsame Eigenschaft mit einem eindeutigen Literalwert (dem sogenannten Diskriminator) teilen. TypeScript erkennt diesen Diskriminator und führt innerhalb von bedingten Blöcken automatisch ein Type Narrowing durch.
interface SuccessResponse {
status: 'success'; // Discriminatore letterale
data: string;
}
interface ErrorResponse {
status: 'error'; // Discriminatore letterale
errorMessage: string;
}
type ApiResponse = SuccessResponse | ErrorResponse;
function handleResponse(response: ApiResponse) {
if (response.status === 'success') {
console.log('Dati ricevuti:', response.data);
} else {
console.error('Si è verificato un errore:', response.errorMessage);
}
}Probier es aus
Esercizio 1: Union-Typen
Deklariere eine Variable namens id, die entweder eine Zahl oder ein String sein kann. Initialisiere sie zuerst mit der Zahl 101 und weise ihr dann den String-Wert 'USER-101' zu.
Hinweis anzeigen
Verwende den Operator | zur Verbindung von number und string bei der Deklaration der let-Variable.
Lösung nach 3 Versuchen verfügbar
Esercizio 2: Einfaches Type Narrowing
Erstelle eine Funktion namens formatInput, die einen Parameter input vom Typ String oder Zahl akzeptiert. Wenn input ein String ist, gib den in Großbuchstaben umgewandelten String zurück. Wenn es eine Zahl ist, gib den mit 2 multiplizierten Wert zurück. Spezifiziere die Typen explizit.
Hinweis anzeigen
Verwende typeof input === 'string' innerhalb eines if-Blocks, um das Verhalten zu steuern.
Lösung nach 3 Versuchen verfügbar
Esercizio 3: Narrowing mit 'in'
Schreibe gegeben den beiden Interfaces Car (mit der Methode drive) und Boat (mit der Methode sail) eine Funktion namens moveVehicle, die einen Parameter vehicle vom Typ Car oder Boat akzeptiert. Wenn vehicle die Eigenschaft drive besitzt, führe die Methode drive() aus. Andernfalls führe die Methode sail() aus.
Hinweis anzeigen
Verwende den Operator in der Form 'drive' in vehicle, um das Interface einzuschränken.
Lösung nach 3 Versuchen verfügbar
Esercizio 4: Diskriminierte Union Shape
Definiere einen Typ Shape, der die Union zweier Typen ist: Circle und Square. Circle hat eine Eigenschaft kind mit dem Wert 'circle' (Literalwert) und einen radius (Zahl). Square hat eine Eigenschaft kind mit dem Wert 'square' (Literalwert) und ein side (Zahl). Schreibe dann eine Funktion getArea, die shape vom Typ Shape akzeptiert und die Fläche als Zahl zurückgibt (für den Kreis Math.PI * radius * radius, für das Quadrat side * side).
Hinweis anzeigen
Verwende shape.kind === 'circle' innerhalb von getArea, um den Typ zu diskriminieren und die korrekte Fläche zu berechnen.
Lösung nach 3 Versuchen verfügbar