TypeScript - Interfaces Génériques

Salut là, futur superstar du codage ! Aujourd'hui, nous allons entreprendre un voyage passionnant dans le monde de TypeScript et explorer une de ses fonctionnalités les plus puissantes : les Interfaces Génériques. Ne vous inquiétez pas si vous êtes nouveau dans la programmation - je serai votre guide amical, et nous avancerons pas à pas. À la fin de cette leçon, vous serez étonné de voir combien vous avez appris !

TypeScript - Generic Interfaces

Quelles sont les Interfaces Génériques ?

Avant de plonger dans les interfaces génériques, récapitulons rapidement ce que sont les interfaces dans TypeScript. Une interface est comme un contrat qui définit la structure d'un objet. Elle nous indique quelles propriétés et méthodes un objet devrait avoir.

Maintenant, imaginez si nous pouvions rendre ces interfaces plus flexibles, capables de travailler avec différents types de données. C'est là que les interfaces génériques entrent en jeu ! Elles nous permettent de créer des interfaces qui peuvent s'adapter à divers types de données, rendant notre code plus réutilisable et polyvalent.

Interface Générique de Base

Commençons avec un exemple simple :

interface Box<T> {
contents: T;
}

let numberBox: Box<number> = { contents: 42 };
let stringBox: Box<string> = { contents: "Hello, TypeScript!" };

Dans cet exemple, Box est une interface générique. Le <T> est comme un placeholder pour un type que nous spécifierons plus tard. Nous pouvons utiliser cette interface pour créer des boîtes qui peuvent contenir différents types d'items :

  • numberBox est une Box qui contient un nombre.
  • stringBox est une Box qui contient une chaîne de caractères.

C'est pas génial ? C'est comme avoir une boîte magique qui peut s'adapter pour contenir ce que nous y mettons !

Plusieurs Paramètres de Type

Les interfaces génériques peuvent avoir plus d'un paramètre de type. regardons un exemple :

interface Pair<T, U> {
first: T;
second: U;
}

let pair1: Pair<number, string> = { first: 1, second: "one" };
let pair2: Pair<boolean, Date> = { first: true, second: new Date() };

Ici, Pair est une interface générique avec deux paramètres de type, T et U. Cela nous permet de créer des paires d'items où chaque item peut être d'un type différent. C'est comme créer un duo dynamique de n'importe quelles deux types que nous voulons !

Interfaces Génériques avec des Méthodes

Les interfaces peuvent également inclure des méthodes, et ces méthodes peuvent utiliser les types génériques. Voici un exemple :

interface Reversible<T> {
data: T[];
reverse(): T[];
}

class NumberArray implements Reversible<number> {
constructor(public data: number[]) {}

reverse(): number[] {
return this.data.slice().reverse();
}
}

let numbers = new NumberArray([1, 2, 3, 4, 5]);
console.log(numbers.reverse()); // Output: [5, 4, 3, 2, 1]

Dans cet exemple, Reversible est une interface générique qui inclut une méthode reverse(). La classe NumberArray implémente cette interface pour les nombres. La beauté de cette approche est que nous pourrions facilement créer des classes similaires pour des chaînes, des objets, ou tout autre type !

Interface Générique comme Type de Fonction

Maintenant, explorons comment nous pouvons utiliser des interfaces génériques pour décrire des types de fonction. C'est là que les choses deviennent vraiment intéressantes !

interface Transformer<T, U> {
(input: T): U;
}

let stringToNumber: Transformer<string, number> = (input) => parseInt(input);

console.log(stringToNumber("42")); // Output: 42

Dans cet exemple, Transformer est une interface générique qui décrit une fonction. Elle prend un input de type T et renvoie une valeur de type U. Nous créons ensuite une fonction stringToNumber qui transforme une chaîne en nombre en utilisant cette interface.

Exemple du Monde Réel : Processeur de Données

Regardons un exemple plus complexe que vous pourriez rencontrer dans la programmation réelle :

interface DataProcessor<T, U> {
processItem(item: T): U;
processArray(items: T[]): U[];
}

class StringToNumberProcessor implements DataProcessor<string, number> {
processItem(item: string): number {
return parseInt(item);
}

processArray(items: string[]): number[] {
return items.map(item => this.processItem(item));
}
}

let processor = new StringToNumberProcessor();
console.log(processor.processItem("42"));          // Output: 42
console.log(processor.processArray(["1", "2", "3"])); // Output: [1, 2, 3]

Dans cet exemple, nous définissons une interface DataProcessor qui peut traiter des items individuels ou des arrays d'items. La classe StringToNumberProcessor implémente cette interface pour convertir des chaînes en nombres. Ce patron est incroyablement utile lorsque vous avez besoin de traiter des données de diverses manières tout en conservant la sécurité des types.

Conclusion

Félicitations ! Vous avez fait un grand pas dans votre voyage TypeScript en apprenant sur les interfaces génériques. Ces outils puissants nous permettent d'écrire du code flexible et réutilisable qui peut travailler avec différents types de données. Souvenez-vous, la pratique rend parfait, donc n'ayez pas peur d'expérimenter avec ces concepts dans vos propres projets.

Voici un tableau de référence rapide des méthodes que nous avons couvertes :

Méthode Description
interface Box<T> Crée une interface générique pour une boîte qui peut contenir n'importe quel type
interface Pair<T, U> Crée une interface générique pour une paire d'items de types différents
interface Reversible<T> Crée une interface générique avec une méthode pour inverser un array
interface Transformer<T, U> Crée une interface générique pour une fonction qui transforme un type en un autre
interface DataProcessor<T, U> Crée une interface générique pour traiter des items individuels ou des arrays d'items

Continuez à coder, continuez à apprendre, et souvenez-vous - dans le monde de TypeScript, les génériques sont votre superpouvoir ! ?‍♀️?‍♂️

Credits: Image by storyset