ProgrammationDéveloppeur TypeScript Senior

Qu'est-ce que les Mapped Types en TypeScript et comment les utiliser pour créer des types génériques flexibles ? Développez en détail les nuances de leur utilisation et les pièges potentiels.

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

Les Mapped Types sont des types qui sont construits dynamiquement en transformant (renommant, modifiant) toutes les propriétés d'un autre type. La syntaxe est basée sur la construction in:

type Readonly<T> = { readonly [K in keyof T]: T[K]; } type User = { name: string; age: number; } const u: Readonly<User> = { name: 'Eve', age: 22 }; u.name = 'Bob'; // Erreur : name est en lecture seule

Nuances :

  • Il est possible de modifier les modificateurs (readonly, optional), de les supprimer ou d'en ajouter via les mots-clés -? ou +?.
  • Ils peuvent être appliqués de manière imbriquée, combinés avec des types conditionnels, des types utilitaires et des génériques.
  • Les erreurs ne sont pas toujours faciles à tracer au moment du développement, surtout lors de modifications imbriquées complexes des hiérarchies de types.

Exemple avec tous les modificateurs :

type PartialMutable<T> = { -readonly [K in keyof T]?: T[K]; };

Question piégée.

« En appliquant un mapped type avec le modificateur optionnel, cela influence-t-il seulement les propriétés de premier niveau ou également les objets imbriqués ? »

Réponse : Non, le mapped type avec optionnel ? n'influence QUE les propriétés de premier niveau. Les objets imbriqués doivent être transformés séparément, souvent à l'aide de la récursivité ou de mapped types supplémentaires.

Exemple :

type DeepPartial<T> = { [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K]; };

Exemples d'erreurs réelles dues à l'ignorance des subtilités du sujet.


Histoire

Dans un projet, pour des raisons d'économie de temps, nous avons utilisé le standard Partial<T> pour une forme de profondeur. Cependant, les champs du deuxième et troisième niveau n'étaient pas devenus optionnels, ce qui a conduit à des erreurs inattendues au moment de l'exécution en l'absence de clés imbriquées.


Histoire

Il y a eu une tentative de supprimer les propriétés readonly uniquement dans les objets enfants, en appliquant le mapped type uniquement au niveau supérieur :

type Mutable<T> = { -readonly [K in keyof T]: T[K] }

En conséquence, les champs de type { readonly foo: { readonly bar: number } } sont restés inchangés dans l'imbrication, ce qui a dérouté l'équipe et compliqué la maintenance.


Histoire

Dans un modèle de données complexe, nous avons appliqué des mapped types imbriqués pour la combinaison de plusieurs types utilitaires (par exemple, Readonly & Partial). En raison de l'ordre incorrect de leur composition, des conflits inattendus de compatibilité de types sont survenus, et le compilateur a commencé à produire des messages d'erreur déroutants.