Leçons du module (2/2)
Generics Fondamentaux
Les Generics (programmation générique) sont l'une des fonctionnalités les plus puissantes de TypeScript. Ils permettent d'écrire des composants, des fonctions et des interfaces flexibles et réutilisables qui peuvent fonctionner avec différents types de données, tout en conservant une sécurité des types (type safety) maximale et en évitant l'utilisation d'any.
Les Fonctions Génériques
Pensez à un generic comme à une variable pour les types. Prenons une fonction qui renvoie la valeur passée en argument :
function identity<T>(arg: T): T {
return arg;
}La lettre T (abréviation de Type) est un espace réservé pour le type. Lorsque nous appelons identity, TypeScript capture le type de l'argument passé et définit automatiquement T sur ce type :
const str = identity<string>('Hello'); // T è string
const num = identity(42); // T è number (inferito automaticamente!)Interfaces et Alias Génériques
Les generics peuvent également être appliqués aux interfaces et aux alias de type pour définir des conteneurs ou des structures de données génériques :
interface Box<T> {
content: T;
}
const stringBox: Box<string> = { content: 'TypeScript' };
const numberBox: Box<number> = { content: 42 };Plusieurs Paramètres de Type
Nous pouvons définir des fonctions ou des types qui utilisent plusieurs variables de type (ex. T et U) :
function mergeObjects<T, U>(obj1: T, obj2: U): T & U {
return { ...obj1, ...obj2 };
}Contraintes sur les Generics (Generic Constraints)
Parfois, nous voulons limiter les types acceptés par un generic. Nous pouvons utiliser le mot-clé extends pour ajouter une contrainte (constraint).
Par exemple, si nous voulons que le type générique possède toujours une propriété length (comme les chaînes de caractères ou les tableaux) :
interface HasLength {
length: number;
}
function logLength<T extends HasLength>(arg: T): void {
console.log(arg.length); // Sicuro! Sappiamo che arg ha 'length'
}
logLength('Hello'); // Valido
logLength([1, 2, 3]); // Valido
// logLength(42); // Errore: number non ha la proprietà length!À toi de jouer
Exercice 1 : Fonction Générique Identity
Complète la fonction générique identity afin qu'elle accepte un paramètre value de type générique T et le renvoie sans modification.
Afficher l'indice
Le type de retour doit être le même type générique T que le paramètre.
Solution disponible après 3 tentatives
Exercice 2 : Conteneur Générique Box
Définis une interface générique appelée Box qui accepte un paramètre de type T et possède une unique propriété nommée content de type T.
Afficher l'indice
Utilise la syntaxe interface Box<T> { content: T; }.
Solution disponible après 3 tentatives
Exercice 3 : Contrainte Générique (Constraint)
Écris une fonction générique appelée getLength qui accepte un paramètre arg. arg doit être contraint par une interface qui possède une propriété length (nombre). La fonction doit retourner arg.length.
Afficher l'indice
Déclare la fonction sous la forme getLength<T extends HasLength>(arg: T): number et retourne arg.length.
Solution disponible après 3 tentatives
Exercice 4 : Paire Générique Pair
Définis une interface générique Pair<T, U> avec deux propriétés : first de type T et second de type U. Crée ensuite une fonction générique makePair qui accepte first (de type T) et second (de type U) et renvoie un objet implémentant Pair<T, U>.
Afficher l'indice
Utilise la syntaxe pour deux paramètres génériques Pair<T, U> et définis makePair en conséquence.
Solution disponible après 3 tentatives