Les génériques dans TypeScript
Cet article explique les génériques dans TypeScript.
YouTube Video
Les génériques dans TypeScript
Les génériques dans TypeScript sont une fonctionnalité qui permet de définir des fonctions, des classes et des interfaces réutilisables et sûres, en paramétrant les types. L'utilisation des génériques permet d'écrire du code qui ne dépend pas de types spécifiques, permettant ainsi d'effectuer les mêmes opérations sur différents types.
Bases des génériques
Les génériques agissent comme des modèles qui acceptent des types en tant qu'arguments, permettant aux fonctions et aux classes de gérer différents types.
Fonctions génériques
Voici un exemple de fonction avec des types d'arguments spécifiés à l'aide de génériques.
1function identity<T>(value: T): T {
2 return value;
3}
4
5console.log(identity<number>(42)); // 42
6console.log(identity<string>("Hello")); // Hello
T
est un argument de type générique qui représente les types des arguments et de la valeur de retour de la fonction. Le type réel est déterminé au moment de l'appel de la fonction.- En spécifiant explicitement
<number>
ou<string>
, vous définissez le type.
Les types génériques fonctionnent sans spécification explicite car TypeScript effectue une inférence de type.
1function identity<T>(value: T): T {
2 return value;
3}
4
5console.log(identity(42)); // 42
6console.log(identity("Hello")); // Hello
Contraintes sur les génériques
En imposant des contraintes sur les génériques, vous pouvez les restreindre à n'accepter que des types spécifiques.
1function loggingIdentity<T extends { length: number }>(arg: T): T {
2 console.log(arg.length);
3 return arg;
4}
5
6loggingIdentity("Hello"); // 5
7loggingIdentity([1, 2, 3]); // 3
8
9// loggingIdentity(42); // Error: number does not have a length property.
- En spécifiant
T extends { length: number }
, vous indiquez queT
doit être un type ayant une propriétélength
. Ainsi, les types sans propriétélength
ne seront pas acceptés.
Classes génériques
Les classes peuvent également être définies à l'aide de génériques. Les classes génériques offrent des types flexibles pour les propriétés et les méthodes.
1class Box<T> {
2 private _value: T;
3
4 constructor(value: T) {
5 this._value = value;
6 }
7
8 public getValue(): T {
9 return this._value;
10 }
11
12 public setValue(value: T): void {
13 this._value = value;
14 }
15}
16
17const numberBox = new Box<number>(100);
18console.log(numberBox.getValue()); // 100
19
20const stringBox = new Box<string>("Hello");
21console.log(stringBox.getValue()); // Hello
Box<T>
déclare le typeT
utilisé dans la classe comme générique. Cela permet de réutiliser la même classe pour différents types.
Interfaces génériques
Les génériques peuvent également être utilisés avec des interfaces.
1interface Pair<T, U> {
2 first: T;
3 second: U;
4}
5
6const numberStringPair: Pair<number, string> = { first: 1, second: "One" };
7console.log(numberStringPair); // { first: 1, second: 'One' }
8
9const booleanArrayPair: Pair<boolean, number[]> = { first: true, second: [1, 2, 3] };
10console.log(booleanArrayPair); // { first: true, second: [ 1, 2, 3 ] }
- En spécifiant deux types génériques avec
Pair<T, U>
, vous pouvez définir un objet combinant différents types.
Arguments de type par défaut
Il est également possible de spécifier un type par défaut pour les arguments de type générique.
1function createArray<T = string>(length: number, value: T): T[] {
2 return Array(length).fill(value);
3}
4
5console.log(createArray(3, "a")); // ['a', 'a', 'a']
6console.log(createArray(3, 100)); // [100, 100, 100]
- Nous définissons l'argument de type par défaut comme
string
avec<T = string>
. Si aucun type n'est spécifié explicitement,T
sera de typestring
.
Alias de type générique
Les génériques peuvent également être utilisés comme alias de type (type
).
1type Result<T> = {
2 success: boolean;
3 data: T;
4};
5
6const successResult: Result<number> = { success: true, data: 42 };
7const errorResult: Result<string> = { success: false, data: "Error occurred" };
8
9console.log(successResult); // { success: true, data: 42 }
10console.log(errorResult); // { success: false, data: 'Error occurred' }
Result<T>
représente un objet de résultat contenant des données de typeT
. De cette manière, vous pouvez créer des alias de type flexibles à l'aide de génériques.
Types génériques multiples
En utilisant plusieurs types génériques, vous pouvez définir des fonctions et des classes encore plus polyvalentes.
1function merge<T, U>(obj1: T, obj2: U): T & U {
2 return { ...obj1, ...obj2 };
3}
4
5const person = { name: "Alice" };
6const job = { title: "Engineer" };
7
8const merged = merge(person, job);
9console.log(merged); // { name: 'Alice', title: 'Engineer' }
- La fonction
merge
prend deux types différentsT
etU
et les combine pour retourner un nouvel objet.
Résumé
- Les génériques permettent d'écrire du code réutilisable et sûr en manipulant les types comme des paramètres.
- En utilisant des génériques dans les fonctions, classes et interfaces, vous pouvez écrire une logique flexible qui gère divers types.
- En ajoutant des contraintes aux arguments de type ou en définissant des arguments de type par défaut, vous pouvez contrôler la portée des génériques.
En utilisant des génériques, vous pouvez écrire du code indépendant des types et polyvalent, en exploitant au maximum le puissant système de types de TypeScript.
Vous pouvez suivre l'article ci-dessus avec Visual Studio Code sur notre chaîne YouTube. Veuillez également consulter la chaîne YouTube.