Types mappés TypeScript
Les types mappés sont une fonctionnalité puissante de TypeScript pour créer de nouveaux types à partir de types existants.
Ils permettent aux développeurs de modifier les caractéristiques des propriétés par lots, comme rendre toutes les propriétés optionnelles ou toutes les propriétés readonly.
Les types mappés sont la technologie centrale pour implémenter les types utilitaires intégrés de TypeScript.
Diagramme SVG : Comment fonctionnent les types mappés
Pourquoi avons-nous besoin des types mappés
Dans le développement pratique de TypeScript, nous devons souvent créer des variantes basées sur des types existants.
Par exemple, une version où toutes les propriétés sont optionnelles, ou une version où toutes les propriétés sont readonly.
La méthode traditionnelle consiste à définir ces types manuellement, ce qui est fastidieux et source d'erreurs.
Les types mappés fournissent un moyen déclaratif de générer automatiquement ces variantes de types.
Explication du concept :Les types mappés utilisent
keyofetinle mot-clé pour itérer sur toutes les clés d'un type existant, puis appliquer la même transformation de type à chaque clé.
Types mappés de base
Les types mappés de base créent de nouveaux types en itérant sur toutes les clés du type d'origine.
C'est la base pour implémenter des types utilitaires comme Partial et Readonly.
Exemple
interface User {
// ID utilisateur
id: number;
// Nom d'utilisateur
name: string;
// E-mail de l'utilisateur
email: string;
}
// Implémenter le type utilitaire Partial
// Itérer sur toutes les clés de T, ajouter le modificateur optionnel ?
type Partial<T> = {
// P itère sur toutes les clés renvoyées par keyof T
// T[P] obtient le type de valeur de la clé correspondante dans le type d'origine
[P in keyof T]?: T[P];
};
// Utiliser le type Partial
type PartialUser = Partial<User>;
// Le type PartialUser est équivalent à :
// { id?: number; name?: string; email?: string }
// Seules des propriétés partielles peuvent être fournies
var user: PartialUser = { name: "Alice" };
console.log("Utilisateur partiel : " + JSON.stringify(user));
Sortie :
部分用户: {"name":"Alice"}
Explication de la syntaxe :
[P in keyof T]Indique l'itération sur toutes les clés du type T.?Le modificateur rend les propriétés optionnelles.
Modificateurs de propriété
Les types mappés prennent en charge plusieurs modificateurs de propriété pour modifier les caractéristiques des propriétés.
Ces modificateurs peuvent être combinés pour répondre à différents besoins de transformation de type.
Exemple
interface User {
// Nom d'utilisateur
name: string;
// Âge de l'utilisateur
age: number;
}
// Utiliser le mappage readonly : rendre toutes les propriétés readonly
// Ajouter le modificateur readonly
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
// Utiliser le mappage optionnel : rendre toutes les propriétés optionnelles (version de base)
type Optional<T> = {
[P in keyof T]?: T[P];
};
// Utiliser le mappage -? : supprimer le modificateur optionnel (rendre obligatoire)
// -? supprime le modificateur ? d'origine
type Required<T> = {
[P in keyof T]-?: T[P];
};
// Tester le type readonly
var readonlyUser: Readonly<User> = { name: "Alice", age: 25 };
// readonlyUser.age = 30; // Erreur : une propriété en lecture seule ne peut pas être modifiée
// Tester le type optionnel
var optionalUser: Optional<User> = { name: "Bob" };
console.log("Lecture seule : " + JSON.stringify(readonlyUser));
console.log("Optionnel : " + JSON.stringify(optionalUser));
Sortie :
只读: {"name":"Alice","age":25}
可选: {"name":"Bob"}
Description du modificateur :
?ajoute facultatif,-?supprime facultatif ;readonlyajoute readonly,-readonlysupprime readonly.
Remappage des clés
Les types mappés peuvent aussi utiliserasle mot-clé pour remapper les noms de clés.
Ceci est utile lorsque vous devez modifier uniformément les formats des noms de clés.
Exemple
interface User {
// ID utilisateur
id: number;
// Nom d'utilisateur
name: string;
// Âge de l'utilisateur
age: number;
}
// Utiliser le mot-clé as pour remapper les noms de clés
// Ajouter un préfixe à toutes les clés
type WithPrefix<T, Prefix extends string> = {
// Utiliser les types de littéraux de modèle pour renommer les clés
// Capitalize met la première lettre en majuscule
[P in keyof T as `${Prefix}${Capitalize<string & P>}`]: T[P];
};
// Utiliser WithPrefix pour ajouter le préfixe "user"
type PrefixedUser = WithPrefix<User, "user">;
// Type converti :
// { userId: number; userName: string; userAge: number }
// Utiliser le type avec préfixe
var user: PrefixedUser = { userId: 1, userName: "Alice", userAge: 25 };
console.log("Avec préfixe : " + JSON.stringify(user));
Sortie :
带前缀: {"userId":1,"userName":"Alice","userAge":25}
Types de littéraux de modèle :Utiliser
`${Prefix}${Capitalizepeuvent générer dynamiquement de nouveaux noms de clés.}`
Filtrage des clés
En combinant les types conditionnels et les types mappés, le filtrage des clés peut être réalisé.
Ceci est très utile lors de l'implémentation de types utilitaires comme Omit.
Exemple
interface User {
// ID utilisateur
id: number;
// Nom d'utilisateur
name: string;
// Mot de passe utilisateur
password: string;
// E-mail de l'utilisateur
email: string;
}
// Implémenter Omit : exclure les clés spécifiées
// Utiliser les types conditionnels pour filtrer les clés
type Omit<T, K extends keyof T> = {
// P parcourt toutes les clés de T
// Si P est assignable à K (c'est-à-dire, dans la liste d'exclusion), retourner never (exclu)
// Sinon, retourner P (conserver la clé)
[P in keyof T as P extends K ? never : P]: T[P];
};
// Utiliser Omit pour exclure la clé password
type UserWithoutPassword = Omit<User, "password">;
// Type converti :
// { id: number; name: string; email: string }
// Utiliser le type après avoir exclu password
var user: UserWithoutPassword = { id: 1, name: "Alice", email: "[email protected]" };
console.log("Sans mot de passe : " + JSON.stringify(user));
Sortie :
无密码: {"id":1,"name":"Alice","email":"[email protected]"}
type never :Dans les types mappés, utiliser never comme type de propriété entraîne la suppression complète de la propriété.
Mappage conditionnel
Les types mappés peuvent être combinés avec des types conditionnels pour appliquer différentes transformations en fonction des types de propriétés.
Cela rend la transformation de type plus flexible et intelligente.
Exemple
interface APIResponse {
// Données de réponse
data: string;
// Message d'erreur
error: string;
// Si en cours de chargement
isLoading: boolean;
// Horodatage
timestamp: number;
}
// Convertir les types de fonction en () => void
// Parcourir toutes les propriétés et effectuer une conversion conditionnelle selon le type de propriété
type FunctionToVoid<T> = {
// Si T[P] est un type de fonction, le convertir en () => void
// Sinon, conservez le type d'origine inchangé
[P in keyof T]: T[P] extends (...args: any[]) => any
? () => void
: T[P];
};
// Utiliser le mappage conditionnel
var response: FunctionToVoid<APIResponse> = {
data: "hello",
error: "",
isLoading: false,
timestamp: Date.now()
};
console.log("Response: " + JSON.stringify(response));
Sortie :
响应: {"data":"hello","error":"","isLoading":false,"timestamp":...}
Scénarios d'application :Le mappage conditionnel est souvent utilisé dans des scénarios où un traitement différent est nécessaire selon les types, comme le traitement des réponses d'API ou le nettoyage d'objets de configuration.
Types mappés intégrés
TypeScript dispose de nombreux types utilitaires intégrés implémentés à partir de types mappés.
Ces types utilitaires peuvent satisfaire la plupart des besoins quotidiens de développement.
Exemple
type P1 = Partial<{ a: string; b: number }>;
// Résultat : { a?: string; b?: number }
// Required - rend obligatoires toutes les propriétés optionnelles
type R1 = Required<{ a?: string; b?: number }>;
// Résultat : { a: string; b: number }
// Readonly - rend toutes les propriétés readonly
type RO1 = Readonly<{ a: string; b: number }>;
// Résultat : { readonly a: string; readonly b: number }
// Pick - Sélectionne les propriétés spécifiées
type PK = Pick<{ a: string; b: number; c: booléen }, "a" | "b">;
// Résultat : { a: string; b: number }
// Omit - Exclut les propriétés spécifiées
type OM = Omit<{ a: string; b: number; c: booléen }, "c">;
// Résultat : { a: string; b: number }
// Test Partial
console.log("Partial: " + JSON.stringify({} as P1));
// Test Pick
console.log("Pick: " + JSON.stringify({ a: "x" } as PK));
Combinaisons de types utilitaires :Ces types utilitaires intégrés sont tous implémentés à partir de types mappés et de types conditionnels. Comprendre leur fonctionnement peut vous aider à mieux les utiliser.
Notes
- mot-clé keyof :Utilisé pour obtenir un type union composé de toutes les clés d'un type.
- mot-clé in :Utilisé pour itérer sur des types union de noms de clés.
- Position du modificateur :
?etreadonlyAvant le nom de la propriété, indique l'ajout d'un modificateur. - Modificateur moins :
-?et-readonlyUtilisé pour supprimer des modificateurs. - mot-clé as :Utilisé pour remapper les noms de clés ; doit renvoyer un type littéral de chaîne ou numérique.
Avancé :Les types mappés peuvent être combinés avec des types conditionnels et des types littéraux de modèle pour implémenter des transformations de type complexes.
Résumé
Les types mappés sont l'une des fonctionnalités les plus puissantes du système de types de TypeScript.
- keyof:Obtenir toutes les clés d'un type
- in:Parcourir les noms de clés pour le mappage
?:Ajouter des modificateurs optionnels- readonly:Ajouter des modificateurs readonly
- -?:Supprimer les modificateurs optionnels
- as:Remapper les noms de clés
Bonnes pratiques :Utiliser judicieusement les types mappés peut considérablement réduire les définitions de type répétitives et améliorer la maintenabilité du code.
Autres extensions