Leçons du module (2/2)
Unions et Narrowing
Dans le monde réel, les variables et les réponses des API n'ont pas toujours un seul type fixe. TypeScript propose les Types Union (Union Types) pour gérer la variabilité, et le Rétrécissement de Type (Type Narrowing) pour travailler sur ceux-ci en toute sécurité au moment de l'exécution.
Types Union (Union Types)
Un type unione permet à une variable d'accepter des valeurs de différents types. Il est exprimé à l'aide de la barre verticale (|) :
let result: number | string;
result = 42; // Valido
result = 'Errore 404'; // ValidoCependant, lorsque nous travaillons avec un type union, nous ne pouvons pas appeler directement des méthodes qui n'appartiennent qu'à l'un des types (par exemple, nous ne pouvons pas faire .toUpperCase() si la variable peut également être un number). Nous devez d'abord "rétrécir" le type.
Rétrécissement de Type (Type Narrowing)
Le Type Narrowing est le processus par lequel TypeScript analyse les structures de contrôle de flux (comme if ou switch) pour en déduire un type plus spécifique pour une variable au moment de l'exécution.
Il existe plusieurs manières d'effectuer le narrowing :
1. Opérateur typeof
Idéal pour distinguer les types primitifs :
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. Opérateur in
Utilisé pour vérifier la présence d'une propriété spécifique dans un objet :
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
}
}Unions Discriminées (Discriminated Unions)
Le modèle des Unions Discriminées consiste à créer des objets qui partagent une propriété commune avec une valeur littérale unique (appelée discriminateur). TypeScript reconnaît ce discriminateur et effectue le narrowing automatique à l'intérieur des blocs conditionnels.
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);
}
}À toi de jouer
Exercice 1 : Union de Types
Déclare une variable nommée id qui peut être soit un nombre, soit une chaîne de caractères. Initialise-la d'abord avec le nombre 101, puis assigne la valeur de chaîne 'USER-101'.
Afficher l'indice
Utilise l'opérateur | pour unir number et string dans la déclaration de la variable let.
Solution disponible après 3 tentatives
Exercice 2 : Type Narrowing De Base
Crée une fonction appelée formatInput qui accepte un paramètre input de type string ou number. Si input est une chaîne, retourne input converti en majuscules. S'il s'agit d'un nom, retourne input multiplié par 2. Spécifie les types explicitement.
Afficher l'indice
Utilise typeof input === 'string' à l'intérieur d'un bloc if pour distinguer le comportement.
Solution disponible après 3 tentatives
Exercice 3 : Narrowing avec 'in'
Étant donné les deux interfaces Car (avec la méthode drive) et Boat (avec la méthode sail), écris une fonction appelée moveVehicle qui accepte un paramètre vehicle de type Car ou Boat. Si vehicle a la propriété drive, exécute la méthode drive(). Sinon, exécute la méthode sail().
Afficher l'indice
Utilise l'opérateur in sous la forme 'drive' in vehicle pour faire le narrowing de l'interface.
Solution disponible après 3 tentatives
Exercice 4 : Union Discriminée Shape
Définis un type Shape qui est l'union de deux types : Circle et Square. Circle a une propriété kind définie sur 'circle' (valeur littérale) et un radius (nombre). Square a une propriété kind définie sur 'square' (valeur littérale) et un side (nombre). Écris ensuite une fonction getArea qui accepte shape de type Shape et retourne l'aire sous forme de nombre (pour le cercle Math.PI * radius * radius, pour le carré side * side).
Afficher l'indice
Utilise shape.kind === 'circle' à l'intérieur de getArea pour discriminer le type et calculer l'aire correcte.
Solution disponible après 3 tentatives