TypeScript - Génériques : Un Guide Pour Les Débutants

Bonjour là-bas, future superstar du codage ! Aujourd'hui, nous allons entreprendre un voyage passionnant dans le monde des génériques TypeScript. Ne vous inquiétez pas si vous êtes nouveau dans le programme - je serai votre guide amical, et nous avancerons pas à pas. À la fin de ce tutoriel, vous utiliserez les génériques comme un pro !

TypeScript - Generics

Qu'est-Ce Que Les Génériques et Pourquoi Devrions-Nous Nous En Soucier ?

Avant de plonger dans les détails, penchons-nous sur une simple analogie. Imaginez que vous avez une boîte magique qui peut contenir tout type d'objet. Parfois, vous mettez dedans un livre, parfois un jouet, ou même un sandwich. C'est essentiellement ce que sont les génériques dans TypeScript - ils nous permettent de créer du code flexible et réutilisable qui peut fonctionner avec différents types.

Exemples De Problèmes

Jetons un coup d'œil à quelques scénarios où les génériques peuvent sauver la situation :

  1. Vous voulez créer une fonction qui peut inverser tout type de tableau (nombres, chaînes, objets).
  2. Vous avez besoin d'une classe qui peut stocker et récupérer tout type de données.
  3. Vous êtes en train de construire une fonction utilitaire qui devrait fonctionner avec divers types de données.

Sans les génériques, vous devriez écrire des fonctions ou des classes séparées pour chaque type de données. C'est beaucoup de répétition, et comme tout bon programmeur le sait, la répétition est l'ennemi du code propre !

Les Génériques TypeScript Au Secours !

Maintenant, mettons les mains dans le cambouis et voyons comment les génériques fonctionnent en action.

Fonction Générique De Base

Voici une fonction générique simple qui peut fonctionner avec n'importe quel type :

function identity<T>(arg: T): T {
return arg;
}

Reprenons cela :

  • <T> est notre paramètre de type. C'est comme un placeholder pour le type que nous utiliserons.
  • (arg: T) signifie que notre fonction prend un argument de type T.
  • : T après les parenthèses signifie que notre fonction renverra une valeur de type T.

Nous pouvons utiliser cette fonction comme suit :

let output1 = identity<string>("Hello, Génériques !");
let output2 = identity<number>(42);

console.log(output1); // "Hello, Génériques !"
console.log(output2); // 42

Cool, non ? La même fonction fonctionne avec différents types !

Interface Générique

Nous pouvons également utiliser les génériques avec des interfaces. Voici un exemple :

interface GenericBox<T> {
contents: T;
}

let stringBox: GenericBox<string> = { contents: "Un message secret" };
let numberBox: GenericBox<number> = { contents: 123 };

console.log(stringBox.contents); // "Un message secret"
console.log(numberBox.contents); // 123

Notre GenericBox peut contenir tout type de contenu. C'est comme cette boîte magique dont nous avons parlé plus tôt !

Classes Génériques

Créons une classe générique qui peut fonctionner comme un simple stockage de données :

class DataStore<T> {
private data: T[] = [];

addItem(item: T): void {
this.data.push(item);
}

getItems(): T[] {
return this.data;
}
}

let stringStore = new DataStore<string>();
stringStore.addItem("Hello");
stringStore.addItem("World");
console.log(stringStore.getItems()); // ["Hello", "World"]

let numberStore = new DataStore<number>();
numberStore.addItem(1);
numberStore.addItem(2);
console.log(numberStore.getItems()); // [1, 2]

Cette classe DataStore peut stocker et récupérer tout type de données. Pretty handy, huh ?

Contraintes Génériques

Parfois, nous voulons restreindre les types qui peuvent être utilisés avec nos génériques. Nous pouvons le faire avec des contraintes :

interface Lengthy {
length: number;
}

function logLength<T extends Lengthy>(arg: T): void {
console.log(arg.length);
}

logLength("Hello"); // 5
logLength([1, 2, 3]); // 3
logLength({ length: 10 }); // 10
// logLength(123); // Erreur : Number n'a pas une propriété length

Ici, notre fonction logLength ne peut fonctionner qu'avec des types qui ont une propriété length.

Avantages Des Génériques

Maintenant que nous avons vu les génériques en action, résumons leurs avantages :

  1. Réutilisabilité Du Code : Écrivez une fois, utilisez avec de nombreux types.
  2. Sécurité Du Type : Attrapez les erreurs liées aux types au moment de la compilation.
  3. Flexibilité : Créez des composants qui peuvent fonctionner avec une variété de types de données.
  4. Clarté : Rendez les relations entre les entrées et les sorties claires.

Table Des Méthodes Génériques

Voici un tableau pratique de quelques méthodes génériques que vous pourriez rencontrer :

Méthode Description Exemple
Array.map<U>() Transforme les éléments du tableau [1, 2, 3].map<string>(n => n.toString())
Promise.all<T>() Attend la résolution de toutes les promesses Promise.all<number>([Promise.resolve(1), Promise.resolve(2)])
Object.keys<T>() Obtient les clés de l'objet sous forme de tableau Object.keys<{name: string}>({name: "Alice"})
JSON.parse<T>() Analyser une chaîne JSON en un objet JSON.parse<{age: number}>('{"age": 30}')

Conclusion

Félicitations ! Vous avez appena fait vos premiers pas dans le merveilleux monde des génériques TypeScript. Souvenez-vous, comme avec tout outil puissant, les génériques peuvent sembler un peu délicats au début, mais avec de la pratique, ils deviendront une seconde nature.

Alors que vous continuez votre voyage de codage, vous découvrirez que les génériques sont comme un couteau suisse dans votre boîte à outils TypeScript - polyvalent, puissant et incroyablement utile. Alors, continuez de coder, jeune padawan, et que les génériques soient avec vous !

Bonne programmation, et jusqu'à la prochaine fois, continuez à explorer et à apprendre !

Credits: Image by storyset