Types de marque en TypeScript

Lorsque vous modélisez des entités avec TypeScript, il est très courant d’obtenir une interface comme celle-ci :

TypeScript

 

Le Problème

Les types des propriétés n’ont pas de signification sémantique. En termes de types, User.id, Order.id, Order.year, etc. sont les mêmes : un nombre, et en tant que nombre, ils sont interchangeables, mais sémantiquement, ils ne le sont pas.

En suivant l’exemple précédent, nous pouvons avoir un ensemble de fonctions qui effectuent des actions sur les entités. Par exemple :

TypeScript

 

Ces fonctions accepteront n’importe quel nombre dans n’importe quel argument, peu importe la signification sémantique du nombre. Par exemple :

TypeScript

 

Évidemment, c’est une grosse erreur, et il pourrait sembler facile d’éviter de lire le code, mais le code n’est pas toujours aussi simple que l’exemple.

Il en va de même pour getOrdersFiltered : nous pouvons échanger les valeurs du jour et du mois, et nous n’obtiendrons aucun avertissement ou erreur. Les erreurs se produiront si le jour est supérieur à 12, mais il est évident que le résultat ne sera pas celui attendu.

La Solution

Les règles de la callisthénie des objets fournissent une solution à cela : envelopper tous les primitifs et les chaînes (anti-modèle d’obsession des primitifs liés). La règle est d’envelopper les primitifs dans un objet qui représente une signification sémantique (DDD décrit cela comme ValueObjects).

Mais avec TypeScript, nous n’avons pas besoin d’utiliser des classes ou des objets pour cela : nous pouvons utiliser le système de types pour garantir qu’un nombre qui représente quelque chose de différent d’une année ne peut pas être utilisé à la place d’une année.

Types Marqués

Ce modèle utilise l’extensibilité des types pour ajouter une propriété qui garantit la signification sémantique :

TypeScript

 

Cette ligne simple crée un nouveau type qui peut fonctionner comme un nombre — mais n’est pas un nombre, c’est une année.

TypeScript

 

Généraliser la solution

Pour éviter d’écrire un type par type de marque, nous pouvons créer un type utilitaire comme :

TypeScript

 

Qui utilise un symbole unique comme nom de propriété de marque pour éviter les conflits avec vos propriétés et obtient le type original et la marque en tant que paramètres génériques.

Avec cela, nous pouvons refactoriser nos modèles et fonctions comme suit :

TypeScript

 

Maintenant, dans cet exemple, l’IDE affichera une erreur car id est un UserId et deleteOrder attend un OrderId.

TypeScript

 

Compromis

Comme petit compromis, vous devrez utiliser X comme Brand. Par exemple, const year = 2012 as Year lorsque vous créez une nouvelle valeur à partir d’un primitif, mais c’est l’équivalent de new Year(2012) si vous utilisez des objets de valeur. Vous pouvez fournir une fonction qui fonctionne comme une sorte de « constructeur » :

TypeScript

 

Validation avec des types de marque

Les types de marque sont également utiles pour garantir que les données sont valides car vous pouvez avoir des types spécifiques pour les données validées, et vous pouvez faire confiance à l’utilisateur d’avoir été validé simplement en utilisant des types :

TypeScript

 

Readonly n’est pas obligatoire, mais pour être sûr que votre code ne modifiera pas les données après les avoir validées, il est fortement recommandé.

Récapitulatif

Les types de marque sont une solution simple qui comprend les éléments suivants :

  • Améliore la lisibilité du code : Rend plus clair quel valeur doit être utilisée dans chaque argument
  • Fiabilité : Aide à éviter les erreurs dans le code qui peuvent être difficiles à détecter ; désormais, l’IDE (et la vérification de type) nous aide à détecter si la valeur est au bon endroit
  • Validation des données : Vous pouvez utiliser des types de marque pour garantir que les données sont valides.

Vous pouvez considérer les types de marque comme une sorte de version de ValueObjects mais sans utiliser de classes — juste des types et des fonctions.

Profitez de la puissance des types !

Source:
https://dzone.com/articles/branded-types-in-typescript