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
Test 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
- Même sans spécifier explicitement
<number>ou<string>, l'inférence de type a lieu.identity(42)est déduit commenumber, etidentity("Hello")est déduit commestring.
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 queTdoit être un type ayant une propriétélength. Ainsi, les types sans propriétélengthne seront pas acceptés.
Combinaison avec keyof
En combinant les génériques avec keyof, vous pouvez obtenir les noms des propriétés de manière sûre au niveau du typage.
1function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
2 return obj[key];
3}
4
5const person = { name: "Bob", age: 30 };
6const personName = getProperty(person, "name"); // string
7console.log(personName);
8
9// const error = getProperty(person, "unknown"); // Error
Kest contraint parkeyof T, ce qui indique que seules les clés existant dansTpeuvent être spécifiées. Spécifier une clé qui n'existe pas entraînera une erreur de compilation.
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 typeTutilisé 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
stringavec<T = string>. Si aucun type n'est spécifié explicitement,Tsera 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
mergeprend deux types différentsTetUet 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.