Passer au contenu principal
eLearner.app
Module 3 · Leçon 2 sur 26/14 dans le cours~15 min
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 :

TS
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 :

TS
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 :

TS
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) :

TS
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) :

TS
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

Exercice#ts.m3.l2.e1
Tentatives : 0Chargement…

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.

Chargement de l'éditeur…
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

Exercice#ts.m3.l2.e2
Tentatives : 0Chargement…

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.

Chargement de l'éditeur…
Afficher l'indice

Utilise la syntaxe interface Box<T> { content: T; }.

Solution disponible après 3 tentatives

Exercice 3 : Contrainte Générique (Constraint)

Exercice#ts.m3.l2.e3
Tentatives : 0Chargement…

É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.

Chargement de l'éditeur…
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

Exercice#ts.m3.l2.e4
Tentatives : 0Chargement…

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>.

Chargement de l'éditeur…
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