Fermer

août 27, 2024

Un guide complet pour comprendre le type d’enregistrement TypeScript –

Un guide complet pour comprendre le type d’enregistrement TypeScript –


TypeScript Record type simplifie la gestion des structures d’objets avec des types de valeurs cohérents. Ce guide couvre l’essentiel de Recordy compris sa définition, sa syntaxe et ses différences avec d’autres types comme les tuples. Nous apprendrons à définir et à utiliser Record dans des scénarios pratiques tels que l’application d’un traitement exhaustif des cas et la cartographie des énumérations. De plus, nous explorerons des utilisations avancées en combinant Record avec des types d’utilitaires comme Partial, Picket Readonly.

Introduction

Le Record type est un type utilitaire qui nous permet de créer un type d’objet avec des clés spécifiées et un type de valeur uniforme. Ce type est particulièrement utile pour définir des mappages et garantir que toutes les valeurs d’un objet sont conformes à un seul type.

Définition du type d’enregistrement

La définition officielle du Documentation TypeScript est:

Record<Keys, Type>

Ici:

  • Keys représentent l’ensemble de clés de l’enregistrement, qui peut être une union de chaînes littérales ou un type dérivé d’une union.
  • Type est le type des valeurs associées à ces clés.

Par exemple, Record<string, number> définit un objet où chaque clé est une chaîne et chaque valeur est un nombre. Ce type garantit que toutes les propriétés de l’objet ont le même type de valeur, mais les clés peuvent varier.

Comparaison entre un enregistrement et un tuple

Les deux Record et tuples sont utilisés pour gérer des collections de données, mais ils servent des objectifs différents. Même s’ils stockent plusieurs valeurs, leur structure et leur utilisation diffèrent. Un Record a des propriétés nommées avec un type fixe, alors qu’un tuple est une liste ordonnée d’éléments identifiés par leur position. Voici une comparaison simple :

  • Enregistrer. Crée un type d’objet dans lequel toutes les valeurs ont le même type, mais les clés peuvent être flexibles. Ceci est utile pour mapper les clés aux valeurs et garantir que toutes les clés adhèrent à un type spécifique.
  • Tuple. Définit un tableau avec un nombre fixe d’éléments, où chaque élément peut avoir un type différent. Les tuples sont utilisés lorsque nous avons besoin d’une collection de taille fixe avec des types spécifiques pour chaque position.

Par exemple, considérons ce qui suit.

Voici un Record type, qui mappe les clés de chaîne aux valeurs numériques :

type AgeMap = Record<string, number>;

Un type tuple représente un tableau avec une chaîne (nom) et un nombre (âge) à une position fixe :

type Person = [string, number];

Utilisation de base du type d’enregistrement

Le Record type fournit un moyen simple et efficace de mapper les clés aux valeurs. C’est particulièrement utile lorsque nous devons définir des objets avec des paires clé-valeur spécifiques où les clés sont d’un type particulier et les valeurs sont d’un autre type.

Voici quelques façons de base d’utiliser le Record tapez pour définir et créer des données structurées.

Définir un enregistrement

Pour définir un Recordnous spécifions les types des clés et des valeurs. L’exemple ci-dessous définit un objet où chaque clé est une chaîne et chaque valeur est également une chaîne. Cela pourrait être utilisé pour une carte générique des données utilisateur :

type User = Record<string, string>;

Création d’un Record Exemple de type

Certains sites Web ont plusieurs sous-domaines. Supposons que chacun de ces sous-domaines nécessite un certain niveau d’accès administrateur et créons un Record tapez pour stocker différents rôles d’administrateur et leurs niveaux d’accès correspondants. Ici, UserRoles et UserStatus sont Record types où les clés sont des chaînes littérales spécifiques (admin, blogAdmin, docsAdmin, active, inactive, suspended), et les valeurs sont des chaînes qui décrivent chaque rôle et statut.

Dans un premier temps, nous définissons un Record taper UserRoles avec des rôles d’administrateur spécifiques comme clés et leurs descriptions comme valeurs. Le UserRoles type garantit que tout objet de ce type aura des clés admin, blogAdminet docsAdminavec des valeurs de chaîne décrivant chaque rôle. Le roles L’objet adhère à ce type en fournissant des descriptions pour chaque rôle d’administrateur :

type UserRoles = Record<'admin' | 'blogAdmin' | 'docsAdmin', string>;

const roles: UserRoles = {
  admin: 'General Administrator with access to all areas.',
  blogAdmin: 'Administrator with access to blog content.',
  docsAdmin: 'Administrator with access to documentation.'
};

Ensuite, nous définissons un Record taper UserStatus avec des statuts spécifiques comme clés et leurs descriptions comme valeurs. Le UserStatus type garantit que tout objet de ce type aura des clés active, inactiveet suspendedavec des valeurs de chaîne décrivant chaque statut. Le userStatus L’objet adhère à ce type en fournissant des descriptions pour chaque statut :

type UserStatus = Record<'active' | 'inactive' | 'suspended', string>;

const userStatus: UserStatus = {
  active: 'User is currently active and can use all features.',
  inactive: 'User is currently inactive and cannot access their account.',
  suspended: 'User account is suspended due to policy violations.'
};

En créant Record types de cette manière, nous garantissons que les rôles d’administrateur et les statuts d’utilisateur sont bien définis et cohérents dans toute l’application.

Cas d’utilisation pratique du type d’enregistrement

Dans cette section, nous passerons en revue plusieurs cas d’utilisation pratiques de Record type pour démontrer sa polyvalence et son efficacité dans différents scénarios.

Cas d’utilisation 1 : Application d’une gestion exhaustive des dossiers

En utilisant Record définir un mappage entre les valeurs de cas et les messages nous permet de traiter explicitement chaque cas possible. Cela garantit que tous les cas sont couverts et que tout cas manquant entraînera des erreurs de compilation.

Dans l’exemple ci-dessous, statusMessages est un Record où les clés sont spécifiques Status valeurs ('pending', 'completed', 'failed'), et chaque touche correspond à un message correspondant. Le getStatusMessage La fonction utilise cet enregistrement pour renvoyer le message approprié en fonction du status paramètre. Cette approche garantit que tous les statuts sont traités correctement et de manière cohérente.

Exemple:

type Status = 'pending' | 'completed' | 'failed';

interface StatusInfo {
  message: string;
  severity: 'low' | 'medium' | 'high';
  retryable: boolean;
}

const statusMessages: Record<Status, StatusInfo> = {
  pending: {
    message: 'Your request is pending.',
    severity: 'medium',
    retryable: true,
  },
  completed: {
    message: 'Your request has been completed.',
    severity: 'low',
    retryable: false,
  },
  failed: {
    message: 'Your request has failed.',
    severity: 'high',
    retryable: true,
  },
};

function getStatusMessage(status: Status): string {
  const info = statusMessages[status];
  return `${info.message} Severity: ${info.severity}, Retryable: ${info.retryable}`;
}


console.log(getStatusMessage('completed')); 

Cas d’utilisation 2 : application de la vérification de type dans les applications utilisant des génériques

Les génériques dans TypeScript permettent un code flexible et réutilisable. Lorsqu’il est combiné avec Recordles génériques peuvent aider à appliquer la vérification de type et à garantir que les objets sont conformes à des structures spécifiques.

En utilisant des génériques avec Recordnous pouvons créer des fonctions ou des utilitaires qui génèrent des objets avec un ensemble spécifique de clés et un type de valeur cohérent. Cette approche améliore la sécurité des types et la réutilisabilité dans notre base de code.

Dans l’exemple ci-dessous, le createRecord la fonction prend un tableau de clés et une valeur, et renvoie un Record où chaque clé correspond à la valeur fournie. Cette fonction utilise des génériques (K pour les clés et T pour le type de valeur) pour garantir que le résultat Record a la bonne structure.

Exemple:

function createRecord<K extends string, T>(keys: K[], value: T): Record<K, T> {
  const record: Partial<Record<K, T>> = {};
  keys.forEach(key => record[key] = value);
  return record as Record<K, T>;
}

interface RoleInfo {
  description: string;
  permissions: string[];
}

const userRoles = createRecord(['admin', 'editor', 'viewer'], {
  description: 'Default role',
  permissions: ['read'],
});

console.log(userRoles);

Cas d’utilisation 3 : mappage d’énumérations sur des données

En utilisant Record mapper les énumérations aux données nous permet de créer une table de recherche où chaque valeur d’énumération est associée à des informations spécifiques. Ceci est particulièrement utile pour des scénarios tels que la configuration de paramètres basés sur des valeurs d’énumération.

Dans cet exemple, colorHex est un Record qui cartographie chacun Color enum valeur à son code couleur hexadécimal correspondant. Cette approche fournit un moyen clair et sûr de gérer les données liées aux couleurs en fonction des valeurs d’énumération.

Exemple:

enum Color {
  Red = 'RED',
  Green = 'GREEN',
  Blue = 'BLUE',
  Yellow = 'YELLOW'
}

interface ColorInfo {
  hex: string;
  rgb: string;
  complementary: string;
}

const colorHex: Record<Color, ColorInfo> = {
  [Color.Red]: {
    hex: '#FF0000',
    rgb: 'rgb(255, 0, 0)',
    complementary: '#00FFFF',
  },
  [Color.Green]: {
    hex: '#00FF00',
    rgb: 'rgb(0, 255, 0)',
    complementary: '#FF00FF',
  },
  [Color.Blue]: {
    hex: '#0000FF',
    rgb: 'rgb(0, 0, 255)',
    complementary: '#FFFF00',
  },
  [Color.Yellow]: {
    hex: '#FFFF00',
    rgb: 'rgb(255, 255, 0)',
    complementary: '#0000FF',
  },
};

console.log(colorHex[Color.Green]); 

Cas d’utilisation 4 : création de tables de recherche

Une table de recherche utilisant Record aide à mapper les clés (telles que les identifiants, les noms) à des valeurs spécifiques (telles que les descriptions, les codes). Cela peut être utile pour diverses applications, notamment les configurations, les traductions et bien d’autres choses.

Ici, countryCode est un Record qui mappe les codes de pays à leurs noms de pays, populations, capitales et continents respectifs. Cette table de recherche permet une récupération rapide et sécurisée des noms de pays et des populations en fonction des codes de pays.

Exemple:

type CountryCode = "US" | "CA" | "MX" | "JP";

interface CountryInfo {
  name: string;
  population: number;
  capital: string;
  continent: string;
}

const countryLookup: Record<CountryCode, CountryInfo> = {
  US: {
    name: "United States",
    population: 331000000,
    capital: "Washington D.C.",
    continent: "North America",
  },
  CA: {
    name: "Canada",
    population: 37700000,
    capital: "Ottawa",
    continent: "North America",
  },
  MX: {
    name: "Mexico",
    population: 128000000,
    capital: "Mexico City",
    continent: "North America",
  },
  JP: {
    name: "Japan",
    population: 126300000,
    capital: "Tokyo",
    continent: "Asia",
  },
};

console.log(countryLookup.US);


console.log(countryLookup.US.population);

Itération Record Espèces

Itération Record Les types sont importants pour accéder et manipuler les données dans les structures de données. Créons un exemple de données et montrons diverses méthodes sur la façon dont nous pouvons parcourir le TypeScript Record genres.

Exemples de données :

interface Course {
  professor: string;
  credits: number;
  students: string[];
}

interface Courses {
  [key: string]: Course;
}

const courses: Courses = {
  Math101: {
    professor: "Dr. Eze",
    credits: 3,
    students: ["Emmanuel", "Bob", "Charlie"],
  },
  History201: {
    professor: "Dr. Jones",
    credits: 4,
    students: ["Dave", "Eve"],
  },
};

En utilisant forEach. Pour utiliser forEach avec un Recordconvertissez-le en un tableau de paires clé-valeur :

Object.entries(courses).forEach(([key, value]) => {
  console.log(`${key}: ${value.professor}, ${value.credits}`);
  value.students.forEach(student => {
    console.log(`Student: ${student}`);
  });
});


En utilisant for...in. Le for...in la boucle parcourt les clés d’un Record:

for (const key in courses) {
  if (courses.hasOwnProperty(key)) {
    const course = courses[key];
    console.log(`${key}: ${course.professor}, ${course.credits}`);
    course.students.forEach(student => {
      console.log(`Student: ${student}`);
    });
  }
}


En utilisant Object.keys(). Object.keys() renvoie un tableau de RecordLes clés de :

Object.keys(courses).forEach((key) => {
  const course = courses[key];
  console.log(`${key}: ${course.professor}, ${course.credits}`);
  course.students.forEach(student => {
    console.log(`Student: ${student}`);
  });
});


En utilisant Object.values(). Object.values() renvoie un tableau de RecordLes valeurs de :

Object.values(courses).forEach((course) => {
  console.log(`${course.professor}, ${course.credits}`);
  course.students.forEach(student => {
    console.log(`Student: ${student}`);
  });
});


Types d’utilisation et d’utilitaires avancés avec Record

Le Record Le type peut être combiné avec d’autres types d’utilitaires pour obtenir une plus grande flexibilité et une plus grande sécurité de type. Cette section expose des modèles d’utilisation avancés, démontrant comment Record peut fonctionner avec des types d’utilitaires comme Pick, Readonlyet Partial.

Combinaison Record avec Pick pour le mappage de type sélectif

Le Pick Le type d’utilitaire nous permet de créer un nouveau type en sélectionnant des propriétés spécifiques à partir d’un type existant. Ceci est utile lorsque nous souhaitons travailler uniquement avec un sous-ensemble de propriétés d’un type plus grand.

Ici, nous avons créé un nouveau type SelectedProductInfo en choisissant uniquement le name et price propriétés de la ProductInfo interface, puis en utilisant Record pour mapper différents produits à ce nouveau type :

interface ProductInfo {
  name: string;
  price: number;
  category: string;
}
type SelectedProductInfo = Pick<ProductInfo, "name" | "price">;
type Product = 'Laptop' | 'Smartphone' | 'Tablet';

const products: Record<Product, SelectedProductInfo> = {
  "Laptop": { name: "Dell XPS 15", price: 1500 },
  "Smartphone": { name: "iPhone 12", price: 999 },
  "Tablet": { name: "iPad Pro", price: 799 }
};

Combinaison Record avec Readonly pour les propriétés immuables

Le Readonly Le type d’utilitaire garantit que les propriétés ne peuvent pas être modifiées une fois qu’elles sont définies. Ceci est utile pour créer des structures de données immuables.

Le ReadonlyProductInfo tapez dans l’exemple ci-dessous rend toutes les propriétés de ProductInfo immuable, garantissant que les détails de chaque produit ne peuvent pas être modifiés une fois définis :

type ReadonlyProductInfo = Readonly<ProductInfo>;
const readonlyProducts: Record<Product, ReadonlyProductInfo> = {
  "Laptop": { name: "Dell XPS 15", price: 1500, category: "Electronics" },
  "Smartphone": { name: "iPhone 12", price: 999, category: "Electronics" },
  "Tablet": { name: "iPad Pro", price: 799, category: "Electronics" }
};

Combinaison Record avec Partial pour les propriétés facultatives

Le Partial Le type d’utilitaire rend toutes les propriétés d’un type facultatives. Ceci est utile dans les scénarios dans lesquels toutes les propriétés ne sont pas connues ou requises en même temps.

Ici, le PartialProductInfo type nous permet de créer des produits avec certaines ou aucune des propriétés définies dans ProductInfooffrant une flexibilité dans la manière dont les informations sur le produit sont spécifiées :

type PartialProductInfo = Partial<ProductInfo>;
const partialProducts: Record<Product, PartialProductInfo> = {
  "Laptop": { name: "Dell XPS 15" },
  "Smartphone": { price: 999 },
  "Tablet": {}
};

Combinaison Record avec Record pour le mappage imbriqué

Une autre utilisation avancée consiste à combiner Record types pour créer des mappages imbriqués, ce qui peut être particulièrement utile pour gérer des structures de données complexes.

Dans cet exemple, storeInventory utilise imbriqué Record types pour mapper les départements à leurs produits et détails respectifs, démontrant comment Record peuvent être combinés pour une gestion de données plus complexe :

type Department = 'Electronics' | 'Furniture';
type ProductDetails = Record<Product, ProductInfo>;

const storeInventory: Record<Department, ProductDetails> = {
  "Electronics": {
    "Laptop": { name: "Dell XPS 15", price: 1500, category: "Electronics" },
    "Smartphone": { name: "iPhone 12", price: 999, category: "Electronics" },
    "Tablet": { name: "iPad Pro", price: 799, category: "Electronics" }
  },
  "Furniture": {
    "Chair": { name: "Office Chair", price: 200, category: "Furniture" },
    "Table": { name: "Dining Table", price: 500, category: "Furniture" },
    "Sofa": { name: "Living Room Sofa", price: 800, category: "Furniture" }
  }
};

Conclusion

Le Record type est un outil polyvalent pour gérer et structurer les types d’objets car il nous permet de définir des mappages clairs entre les clés et les valeurs, garantissant ainsi la sécurité des types et la cohérence dans notre code.

Pour des informations plus détaillées, reportez-vous au Documentation TypeScript et consultez d’autres ressources supplémentaires telles que TypeScript total et Tutoriel TypeScript pour approfondir votre compréhension de TypeScript Record système de type.




Source link