Retour aux vidéos

Les Discriminated Union Types : un concept Typescript utile pour améliorer son code

J'ai récemment découvert ce pattern qui m'a permis d'améliorer la qualité et lisibilité de mon code. Il est très utile si tu utilises Typescript, notamment pour les routes POST avec plusieurs actions (éditer, créer, supprimer une donnée ...).

00:00 Découvert un pattern qui me permet d'écrire du code un tout petit peu plus lisible et que je ne connaissais pas jusqu'à présent, alors que ça fait quatre ans que je suis développeur. Et dans cette vidéo, j'ai envie de vous le partager. Peut-être que vous ne le connaissez pas non et ça va également vous aider à améliorer la qualité de votre code. Ce pattern s'appelle le discriminated Union Type et vous allez voir, ça améliore largement la lisibilité de votre base de code. Dès que je l'ai découvert, j'ai tout de commencé à l'implémenter dans mon projet Remix.

00:30 Pour vous faire la démo, j'ai installé un nouveau projet Remix et ce qu'on va faire, c'est qu'on va créer une nouvelle route qu'on va appeler par exemple type point TFX et à l'intérieur de cette route, nous allons ajouter une méthode action et à l'intérieur de ce fichier, nous allons créer un nouveau type et nous allons l'appeler par exemple user actions. Eh bien à l'époque, quand je voulais faire une mutation dans une application remix, ce que je faisais, c'est que je rajoutais un mot clé action ici et je rajoutais le cred de mon utilisateur au sein du même type. Par exemple, ici, on a donc le create, le update et le delete comme ceci. Et ensuite, je mettais tous les autres champs en optionnel. Par exemple, le first name, le last name et ensuite, je devais utiliser Zod pour parser les données en fonction de l'action qui avait été faite.

01:15 Exemple ici, nous allons donc créer notre user qui va hériter de user actions et on va lui donner comme first name Virgile, comme last name algo max et comme action create. Ce type, il est super bien. Mais admettons qu'on ait envie, par exemple, de faire l'édition ou le supprimer cet utilisateur. Si on a envie d'utiliser l'action d'élite comme ceci, on n'a pas forcément besoin de soumettre le first name et le last name à notre utilisateur. On est en train de supprimer cet utilisateur.

01:43 Au contraire, on a besoin d'un autre type de données qui est par exemple son ID. Dans ce cas là, ce que nous pouvons faire à la place, c'est qu'on peut créer trois types différents. On va donc créer le user delead action qui va prendre un user ID et c'est un paramètre obligatoire et une action comme ceci qui va être égale à delete. Maintenant, on peut retirer cette valeur delete de notre user actions comme ceci et ce type là, nous pouvons le renommer en user create action et il prendra obligatoirement un first name et un last name et une action nommée create. Maintenant, on peut très bien dire que cette action, c'est également l'édition de l'utilisateur.

02:21 Mais si on avait envie, par exemple, de modifier seulement le first name et pas le last name, alors dans ce cas-là, on pourrait copier ce type comme ceci, l'appeler user edit action et mettre les deux paramètres en facultatif et nommer cette action edit. Mais dans ce cas-là, comment peut-on savoir quel est le type de données que nous recevons au sein de notre action Bien justement, nous allons grouper ces types-là parce que chacun de ces types possède une même clé nommée action et c'est ce qui va nous permettre de les discriminer. C'est-à-dire là, on va créer un quatrième type qu'on va rappeler user backshims et il est égal comme Copilot nous le suggère à l'un des trois types. Maintenant, on peut voir que j'ai prélevé la valeur d'élite à mon action. Alors, qu'est-ce que ça veut dire Ça veut dire que dans l'action d'élite, on a seulement besoin de soumettre un user edit.

03:07 On n'a pas besoin de soumettre le first name ni le last name. Donc, Lapscript va m'auto-compléter seulement la valeur qui est obligatoire. Par contre, si j'avais à la place utilisé comme valeur l'action de Create, ici on peut voir que ça va changer le type de ma donnée et ça a sélectionné le type qui contient une action qui a comme valeur create, qui est donc le user create action. Ce qui est génial quand on fait ça, c'est qu'on peut donc ensuite créer une fonction qu'on va appeler manage user et qui va prendre un user de ce type-là. Et maintenant, on peut faire un switch sur le user point action.

03:41 Et en fonction de la valeur de cette action, nous sommes sûrs d'avoir l'autocomplétion avec le first name et le last name pour le create. Mais pour le delete, nous avons le typage for sur le user ID. Et bien sûr, sur l'édition, nous avons les deux mêmes paramètres, donc first name et last name, mais en optionnel. Alors pourquoi est-ce que je trouve ce pattern aussi bien Eh bien, c'est parce que ça nous permet d'avoir plusieurs actions sur la même route sans forcément devoir se mettre toutes les données de notre formulaire à chaque fois. À l'époque, il pouvait m'arriver de créer plusieurs routes API pour le delete, pour le edit et pour le create.

04:19 Mais grâce à ce pattern, je peux sur la même route, dans un seul fichier gérer mes trois, mes quatre, mes cinq actions. Maintenant, ce qu'on va faire, c'est qu'on va tout de suite mettre ça en pratique avec un formulaire remix. Et pour ce faire, nous allons tout de suite ouvrir le terminal et nous allons installer Zod et nous allons également installer Conform to Zod et Conform to React, qui est une librairie qui nous permet de gérer les formulaires et de percer les erreurs avec ZAD. Une fois installé, nous allons ajouter notre composant ici et ce que nous pouvons faire, c'est qu'on peut renvoyer un formulaire comme ceci et maintenant, on va se rendre sur notre page que nous allons appeler hype et bien sûr, on lance le projet à nouveau. Ce qui est exceptionnel avec ces types, c'est qu'on va les transformer en schéma Zod et nous allons les nommer comme tels.

05:05 On va donc prendre ce premier type. Nous allons importer Zod. Nous allons dire que c'est un objet et nous allons utiliser Zod. String pour le string et zod point littérale pour notre action. Nous allons répéter l'opération pour nos trois types et pour le dernier type, nous allons mettre que user action est égal à z point union en prenant donc les trois schémas zod que nous venons de créer.

05:27 Maintenant que c'est fait, on va effectuer un parce de ce schéma zod côté serveur. Et pour ce faire, nous devons d'abord récupérer le form data, donc les données du formulaire qu'on vient de soumettre et ensuite nous allons faire un parce with zod qu'on importe depuis la librairie de conforme en lui donnant comme paramètre le form data et ce schéma zod. Bien sûr on sauvegarde cette valeur dans un seul mission et si jamais le statut n'est pas égal à succès alors dans ce cas-là, on peut renvoyer un message d'erreur côté client avec le submission point replay. On va bien sûr importer la méthode JSON et nous allons faire un compte sublog de notre submission avant même de savoir si elle a réussi ou pas. Maintenant, c'est très simple.

06:07 En fonction de l'action qu'on va soumettre, nous saurons s'il y a eu une erreur ou non. Donc ce qu'on va faire, c'est qu'on va ouvrir notre terminal ici et nous allons soumettre le formulaire. Et là, on peut voir qu'on a une petite erreur sur le first name et sur le last name, il n'y a aucun problème. Le serveur a reçu ses valeurs, mais on a oublié notre action. Pour ce faire, nous allons ajouter un nom à notre bouton, il prendra donc comme valeur action et une valeur qui prendra comme valeur create.

06:31 Et dans ce cas-là, normalement, si on se met le formulaire, il ne devrait pas y avoir d'erreur. Mais pour être vraiment sûr, on va quand même rajouter un message d'erreur first name is required, last name is required et là, on va copier cette même pipe de validation et sur le user ID on va mettre un requiord erreur user ID is requiord nous allons aussi le mettre sur l'action comme ça on est prévenu en cas d'erreur dans notre formulaire action everyquiard comme ceci. Maintenant on va soumettre notre formulaire et là on peut voir qu'on a toujours cette erreur et maintenant on devrait bien sûr ajouter des valeurs à ce formulaire. Si on soumet ce formulaire là, là on peut voir qu'on a une erreur parce que en fait on a eu le statut success ici comme on a reçu des valeurs et on a oublié de renvoyer nul ici. Donc ici, on est à ce niveau là et si jamais notre formulaire n'est pas validé, on revoit une erreur.

07:21 Mais s'il est validé, ce cas-là, on peut récupérer l'action qui est contenue dans submission point value. On va la déstructurer comme ceci et nous pouvons de nouveau faire notre switch sur l'action à effectuer avec chacun de nos cases. Donc dans le cas où on fait un case qu'on create, eh bien on va pouvoir déstructurer toutes les valeurs, c'est-à-dire first name et last name de notre objet qui a été par C par ZAD. Si on fait un console log de cette mission. Value et qu'on écrit le code pour les trois cas différents, ici pour le delete et ici pour le edit, on pourra voir dans notre objet qu'il héritera de chacun des types qu'on a défini plus haut ici.

07:57 Il suffit même de faire un survol de souris pour voir sur le edit qu'on a donc une action élite et un first name optionnel et sur le delete, on a un user edit et une action de delete. Et ce qui est marrant, c'est qu'on peut même ajouter cette logique au sein du même formulaire. Je viens de rajouter un bouton pour chacune des actions. Le create qui a comme valeur create, le edit qui a comme valeur edit et le delete est un bouton qui a comme valeur d'élite. Maintenant, on va retourner dans notre action ici, on va supprimer ce console log pour y voir plus clair et on va ouvrir notre terminal.

08:27 Bien sûr, dans ce formulaire-là, on possède toutes les valeurs. On possède un first name, un last name et un user ID. Donc, au moment de le soumettre, si on remplit tous les champs en cliquant sur create, on verra le console log avec l'action create. Il s'effectue donc dans le switch. Ici, c'est le premier console log, mais si on clique sur Edit, on verra que c'est le console log à l'intérieur de Edit qui a été exécuté.

08:50 Ensuite, si on clique sur Elite, on peut voir qu'on a seulement le user ID et l'action qui ont été parcées. Alors, même si les valeurs first name et la SNAM ont été soumises au sein du formulaire, Z n'a parsé et validé que les données qu'on avait définies au sein de ce schéma-là. Après bien sûr, rien ne nous empêche d'écrire la logique de suppression de création de l'utilisateur dans des méthodes séparées. Mais je préfère ce pattern-là d'avoir toutes les actions d'une donnée au sein du même fichier plutôt que d'avoir à créer par exemple ici plusieurs routes comme par exemple type en edit, type point edit et type point create parce qu'au final pour certaines données, ça ne vaut même pas la peine d'optimiser le code. Ici, on peut voir pour cet exemple hyper concret que bien qu'on exécute trois actions différentes dans le même fichier, le code reste plus ou moins lisible ici.

09:39 Si on fait par exemple un await create user, un await delete user et un await edit user, on peut conserver un composant qui est très lisible. Alors, dis-moi ce que tu as pensé de ce pattern. Est-ce que tu le connaissais et est-ce que tu vas l'utiliser pour améliorer le code de ton app N'hésite pas à répondre dans les commentaires. Ça m'intéresse vraiment de savoir si je suis le seul à le découvrir que maintenant. J'espère que cette vidéo t'a été utile et on se retrouve très bientôt.

10:04 À plus.

Vidéos similaires

Rejoins la

newsletter