TypeScript - Types Mappés : Guide du Débutant
Salut à toi, futurs magiciens de TypeScript ! Aujourd'hui, nous allons entreprendre un voyage passionnant à la découverte du monde des Types Mappés. Ne t'inquiète pas si tu es nouveau dans le monde de la programmation - je serai ton guide amical, et nous avancerons pas à pas. D'ici la fin de ce tutoriel, tu seras capable de mapper des types comme un pro !
Qu'est-ce que les Types Mappés ?
Avant de plonger dedans, comprenons ce qu'are les Types Mappés. Imagine que tu as une boîte de chocolates mélangés et que tu veux créer une nouvelle boîte où chaque chocolate est enveloppé dans du papier doré. C'est essentiellement ce que font les Types Mappés dans TypeScript - ils prennent un type existant et le transforment en un nouveau type basé sur un ensemble de règles.
Types Mappés Prédéfinis
TypeScript vient avec quelques Types Mappés prédéfinis qui sont super utiles. Jetons un œil à chacun d'eux :
1. Partial<T>
Le type Partial<T>
rend toutes les propriétés de T
optionnelles. C'est comme passer d'une recette stricte à une recette flexible où tu peux sauter certains ingrédients.
interface Recipe {
name: string;
ingredients: string[];
cookingTime: number;
}
type FlexibleRecipe = Partial<Recipe>;
// Maintenant, nous pouvons créer une recette sans toutes les propriétés
const quickSnack: FlexibleRecipe = {
name: "Toast",
// Nous pouvons sauter ingredients et cookingTime
};
Dans cet exemple, FlexibleRecipe
nous permet de créer une recette sans spécifier toutes les propriétés. C'est parfait lorsque tu veux mettre à jour seulement une partie d'un objet.
2. Required<T>
Required<T>
est l'opposé de Partial<T>
. Il rend toutes les propriétés obligatoires, même si elles étaient optionnelles dans le type original.
interface UserProfile {
name: string;
age?: number;
email?: string;
}
type CompleteUserProfile = Required<UserProfile>;
// Maintenant, nous devons fournir toutes les propriétés
const user: CompleteUserProfile = {
name: "Alice",
age: 30,
email: "[email protected]"
};
Ici, CompleteUserProfile
nous assure que nous fournissons toutes les propriétés, y compris age
et email
qui étaient optionnels dans le UserProfile
original.
3. Readonly<T>
Readonly<T>
rend toutes les propriétés de T
en lecture seule. C'est comme mettre ton type dans une vitrine - tu peux regarder, mais tu ne peux pas toucher !
interface Toy {
name: string;
price: number;
}
type CollectibleToy = Readonly<Toy>;
const actionFigure: CollectibleToy = {
name: "Superhéros",
price: 19.99
};
// Cela provoquera une erreur
// actionFigure.price = 29.99;
Dans cet exemple, une fois que nous avons créé notre actionFigure
, nous ne pouvons pas modifier ses propriétés. C'est génial pour créer des objets immuables.
4. Pick<T, K>
Pick<T, K>
crée un nouveau type en sélectionnant seulement les propriétés spécifiées K
de T
. C'est comme choisir tes fonctionnalités favorites d'un type.
interface Smartphone {
brand: string;
model: string;
year: number;
color: string;
price: number;
}
type BasicPhoneInfo = Pick<Smartphone, 'brand' | 'model'>;
const myPhone: BasicPhoneInfo = {
brand: "TechBrand",
model: "X2000"
};
Ici, BasicPhoneInfo
inclut seulement les propriétés brand
et model
de Smartphone
, laissant les autres de côté.
5. Omit<T, K>
Omit<T, K>
est l'opposé de Pick<T, K>
. Il crée un nouveau type en supprimant les propriétés spécifiées K
de T
.
interface Book {
title: string;
author: string;
pages: number;
isbn: string;
}
type BookPreview = Omit<Book, 'pages' | 'isbn'>;
const preview: BookPreview = {
title: "Aventures TypeScript",
author: "Magicien du Code"
};
Dans ce cas, BookPreview
inclut toutes les propriétés de Book
sauf pages
et isbn
.
Exemples d'utilisation des Types Mappés
Maintenant que nous avons vu les Types Mappés prédéfinis, examinons quelques exemples pratiques de leur utilisation dans des scénarios réels.
Exemple 1 : Création d'un État de Formulaire
Imagine que tu construis un formulaire et que tu veux suivre les champs qui ont été modifiés :
interface LoginForm {
username: string;
password: string;
rememberMe: boolean;
}
type FormTouched = { [K in keyof LoginForm]: boolean };
const touchedFields: FormTouched = {
username: true,
password: false,
rememberMe: true
};
Ici, nous avons créé un type FormTouched
qui a les mêmes clés que LoginForm
, mais toutes les valeurs sont des booléens indiquant si le champ a été touché.
Exemple 2 : Enveloppe de Réponse API
Disons que tu as une API qui renvoie différents types de données, et que tu veux envelopper chaque réponse dans un format standard :
interface ApiResponse<T> {
data: T;
status: 'success' | 'error';
timestamp: number;
}
type UserData = { id: number; name: string; email: string };
type ProductData = { id: number; name: string; price: number };
const userResponse: ApiResponse<UserData> = {
data: { id: 1, name: "John Doe", email: "[email protected]" },
status: 'success',
timestamp: Date.now()
};
const productResponse: ApiResponse<ProductData> = {
data: { id: 101, name: "Laptop", price: 999.99 },
status: 'success',
timestamp: Date.now()
};
Cet exemple montre comment nous pouvons utiliser des génériques avec les Types Mappés pour créer des structures de type flexibles et réutilisables.
Création de Types Mappés Personnalisés
Maintenant, mettons nos muscles TypeScript à l'épreuve et créons quelques Types Mappés personnalisés !
Type Personnalisé 1 : Nullable
Créons un type qui rend toutes les propriétés nullable :
type Nullable<T> = { [K in keyof T]: T[K] | null };
interface Person {
name: string;
age: number;
}
type NullablePerson = Nullable<Person>;
const maybePerson: NullablePerson = {
name: "Jane",
age: null // Cela est maintenant valide
};
Notre type Nullable<T>
permet à toute propriété d'être soit son type original, soit null
.
Type Personnalisé 2 : Freezable
Créons un type qui ajoute une méthode freeze
à un objet :
type Freezable<T> = T & { freeze(): Readonly<T> };
interface Config {
theme: string;
fontSize: number;
}
function makeFreezable<T>(obj: T): Freezable<T> {
return {
...obj,
freeze() {
return Object.freeze({ ...this }) as Readonly<T>;
}
};
}
const config = makeFreezable<Config>({
theme: "dark",
fontSize: 14
});
const frozenConfig = config.freeze();
// frozenConfig.theme = "light"; // Cela provoquera une erreur
Ce type personnalisé ajoute une méthode freeze
à n'importe quel objet, nous permettant de créer une version immuable de celui-ci.
Conclusion
Wahou, nous avons couvert beaucoup de terrain aujourd'hui ! Des Types Mappés prédéfinis à la création de nos propres types personnalisés, tu as vu à quel point TypeScript peut être puissant et flexible. Les Types Mappés sont comme des baguettes magiques dans ton toolkit TypeScript - ils te permettent de transformer et de manipuler des types de manière incroyablement utile.
Souviens-toi, la clé pour maîtriser les Types Mappés est la pratique. Essaie de créer les tiens, expérimente avec différentes combinaisons, et bientôt tu écriras du code TypeScript qui n'est pas seulement fonctionnel, mais élégant et sûr.
Continue de coder, continue d'apprendre, et surtout, amuse-toi avec TypeScript !
Credits: Image by storyset