Types d'index TypeScript et le mot-clé keyof
Les types d'index et keyof sont des outils puissants dans TypeScript pour manipuler les types d'objets.
Ils nous permettent d'accéder dynamiquement aux propriétés d'un objet et de créer des mappages de types flexibles.
Diagramme SVG : comment fonctionnent les types d'index et keyof
Pourquoi avons-nous besoin des types d'index ?
En JavaScript, nous avons souvent besoin d'accéder dynamiquement aux propriétés d'un objet.
Par exemple, une fonction peut avoir besoin d'obtenir toutes les clés d'un objet, ou d'accéder au type de valeur correspondant en fonction d'une clé.
Les types d'index et keyof nous permettent d'exprimer ce dynamisme dans le système de types tout en maintenant la sûreté de typage.
Concept :Les types d'index sont une classe de types qui permettent l'accès dynamique aux propriétés d'un objet, et keyof sert à obtenir un type union composé de toutes les clés d'un type d'objet.
L'opérateur keyof
L'opérateur keyof
Exemple
interface User {
id: number; // ID utilisateur
name: string; // Nom d'utilisateur
email: string; // E-mail
age?: number; // Âge (facultatif)
}
// Utiliser keyof pour obtenir le type union de toutes les clés
// Résultat : "id" | "name" | "email" | "age"
type UserKeys = keyof User;
// Test de keyof
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user: User = {
id: 1,
name: "Alice",
email: "[email protected]"
};
// Récupérer la propriété name
const userName: string = getProperty(user, "name");
console.log("Username: " + userName);
Sortie :
用户名: Alice
Explication :keyof renvoie un type union de littéraux de noms de clés, et non un type string.
Types d'accès indexés
En utilisant les types d'accès indexés, vous pouvez obtenir le type d'une propriété d'objet.
Exemple
interface User {
id: number;
name: string;
email: string;
}
// Utilisez les types d'accès indexés pour obtenir les types de propriétés
type UserId = User["id"]; // number
type UserName = User["name"]; // string
// Vous pouvez utiliser un type union pour accéder à plusieurs clés
type UserIdAndName = User["id" | "name"]; // number | string
// Utilisez keyof pour obtenir l'union de tous les types de propriétés
type AllUserValues = User[keyof User]; // number | string
// Exemple d'utilisation pratique
function getValue<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user: User = { id: 1, name: "Bob", email: "[email protected]" };
// Obtenir le type de id
const idValue: number = getValue(user, "id");
console.log("ID: " + idValue);
// Obtenir le type de name
const nameValue: string = getValue(user, "name");
console.log("Name: " + nameValue);
Accès par index :En utilisant des crochets [] vous pouvez accéder au type d'une propriété spécifique d'un type d'objet ; c'est très puissant et flexible.
Notions de base des types mappés
Les types mappés vous permettent de créer de nouveaux types à partir de types existants en itérant sur toutes leurs clés.
Exemple
interface User {
id: number;
name: string;
email: string;
age: number;
}
// Rendre toutes les propriétés facultatives
type PartialUser = Partial<User>;
// Rendre toutes les propriétés readonly
type ReadonlyUser = Readonly<User>;
// Type mappé personnalisé : rendre toutes les propriétés facultatives et les convertir en chaîne
type Stringify<T> = {
[P in keyof T]: string;
};
type StringifiedUser = Stringify<User>;
// Exemple d'utilisation pratique
const partialUser: PartialUser = {
id: 1,
name: "Alice"
// email et age sont facultatifs
};
const readonlyUser: ReadonlyUser = {
id: 1,
name: "Bob",
email: "[email protected]",
age: 25
};
// readonlyUser.name = "Charlie"; // Erreur : readonly
console.log("Utilisateur partiel : " + partialUser.name);
console.log("Utilisateur en lecture seule : " + readonlyUser.name);
Types mappés :L'utilisation de la syntaxe [P in keyof T] pour parcourir toutes les clés d'un type est la base de la création de types utilitaires.
Contraindre le type des clés
Utilisez keyof et des contraintes génériques pour restreindre les clés qu'une fonction accepte.
Exemple
interface Config {
apiUrl: string;
timeout: number;
retry: boolean;
}
// Ne peut récupérer que les clés existantes
function getConfigValue<T, K extends keyof T>(
config: T,
key: K
): T[K] {
return config[key];
}
// Définir la configuration
const config: Config = {
apiUrl: "https://api.example.com",
timeout: 5000,
retry: true
};
// Correct : la clé existe
const url: string = getConfigValue(config, "apiUrl");
const timeoutVal: number = getConfigValue(config, "timeout");
// Erreur : la clé n'existe pas (TypeScript signalera une erreur)
// const invalid = getConfigValue(config, "unknown");
console.log("URL de l'API : " + url);
console.log("Délai d'attente : " + timeoutVal);
Contrainte :K extends keyof T garantit que la clé passée doit être une clé qui existe sur l'objet, ce qui évite les erreurs d'exécution.
Obtenir uniquement les propriétés d'un type spécifique
Extraire les clés de propriétés d'un type spécifique à partir d'un type d'objet.
Exemple
interface Mixed {
id: number;
name: string;
age: number;
email: string;
active: boolean;
}
// Extraire toutes les clés de type string
type StringKeys<T> = {
[K in keyof T]: T[K] extends string ? K : never;
}[keyof T];
// Extraire toutes les clés de type number
type NumberKeys<T> = {
[K in keyof T]: T[K] extends number ? K : never;
}[keyof T];
// Test
type StringProps = StringKeys<Mixed>; // "name" | "email"
type NumberProps = NumberKeys<Mixed>; // "id" | "age"
// Application pratique : obtenir la valeur d'une propriété de type string
function getStringProps<T, K extends StringKeys<T>>(
obj: T,
keys: K[]
): T[K][] {
return keys.map(key => obj[key]);
}
const mixed: Mixed = {
id: 1,
name: "Alice",
age: 25,
email: "[email protected]",
active: true
};
const strings = getStringProps(mixed, ["name", "email"]);
console.log("Propriétés des chaînes : " + strings.join(", "));
Types conditionnels :La combinaison des types conditionnels et des types mappés permet un filtrage et une extraction de types complexes.
Itération sur les types de tableaux
Utilisez les types d’index pour manipuler des tableaux et des tuples.
Exemple
type Tuple = [string, number, boolean];
// Obtenir le type d’élément du tuple
type First = Tuple[0]; // string
type Second = Tuple[1]; // number
type Third = Tuple[2]; // boolean
// Utiliser number pour obtenir le type de tous les éléments
type AllElements = Tuple[number]; // string | number | boolean
// Obtenir le type d'élément de tableau
type StringArray = string[];
type ArrayElement = StringArray[number]; // string
// Application pratique : surcharges de fonctions
function getElement<T extends any[]>(
arr: T,
index: number
): T[indexof T] | undefined {
return index < arr.length ? arr[index] : undefined;
}
const tuple: Tuple = ["hello", 123, true];
const arr: string[] = ["a", "b", "c"];
console.log("Élément de tuple + getElement(tuple, 0));
console.log("Élément de tableau + getElement(arr, 1));
Indexation de tuple :Les tuples peuvent utiliser des indices numériques, et chaque indice correspond à un type d'élément spécifique, ce que les tableaux ne peuvent pas faire.
Notes
- keyof renvoie un type union :keyof renvoie un type union de littéraux de noms de clés
- Sécurité de l'accès par index :S'assurer que la clé accédée existe dans le type cible
- Contraintes génériques :Utiliser extends keyof pour contraindre les paramètres génériques
- Les types mappés nécessitent le mot-clé in :Les types mappés utilisent la syntaxe [P in keyof T]
Bonnes pratiques :Les types d'index sont la pierre angulaire de la création de types utilitaires génériques ; les maîtriser peut grandement améliorer vos capacités de manipulation de types.
Résumé
Les types d'index et keyof sont des composants importants du système de types de TypeScript.
- keyof:Obtenir toutes les clés d'un type d'objet
- Accès par index :Obtenir les types de propriétés via les clés
- Types mappés :Créer de nouveaux types à partir de types existants
- Sécurité de type :Assurer la sécurité de type pour l'accès dynamique aux propriétés
Autres extensionsRecommandation :Lorsque vous devez manipuler les propriétés d'un objet, privilégiez l'utilisation des types d'index pour maintenir la sécurité de type.