Fermer

septembre 16, 2023

Correspondance de motifs avec TypeScript

Correspondance de motifs avec TypeScript


Découvrez comment la correspondance de modèles est une solution plus fiable pour les instructions conditionnelles complexes que if-else.

Le logiciel est en constante évolution. Les entreprises ajoutent constamment de nouvelles fonctionnalités ou suppriment celles qui sont obsolètes. Au fil du temps, les exigences logicielles sont devenues plus dynamiques. C’est pourquoi la lisibilité du code est un sujet si brûlant de nos jours.

La lisibilité du code est essentielle dans la façon dont les logiciels sont écrits aujourd’hui. Il présente de nombreux avantages, tels que la maintenabilité (le code devient plus facile à maintenir), l’évolutivité (on peut ajouter de nouvelles fonctionnalités sans aucun problème), la collaboration (de nombreux développeurs peuvent travailler et lire le code), etc.

Il est essentiel que chaque fois que nous commençons à travailler sur quelque chose de nouveau pour une application, nous utilisions les meilleures pratiques et modèles de code. Nous devons nous rappeler que de nombreuses personnes à l’avenir pourraient lire notre code, donc écrire du code lisible devrait être une priorité.

La question devient alors de savoir comment écrire du code lisible. Quelles sont les pratiques et modèles de code les plus importants que nous pouvons utiliser pour garantir la lisibilité de notre code ? Outre les pratiques bien connues qui améliorent la lisibilité du code (révision du code, tests, documentation, noms significatifs), nous pouvons utiliser certains modèles de code pour rendre notre code plus lisible.

Avant d’aborder un modèle de code spécifique qui peut nous aider en termes de lisibilité, expliquons d’abord le problème. Nous allons voir pourquoi les instructions if-else peuvent parfois nuire à notre code.

La question des instructions if-else et de la lisibilité

Lorsque nous commençons à écrire du code, l’une des premières choses que nous apprenons est comment écrire correctement une instruction if-else. Ils constituent un excellent code pour déterminer si une expression est vraie ou fausse.

var num = 1;

if (num === 1) {
 console.log("True :)");
}
else {
 console.log("False :(");
}

Les déclarations if-else sont grandioses en raison de leur simplicité. Nous pouvons facilement comprendre ce qui se passe dans notre code sans une compréhension approfondie de la programmation.

Le problème est que les instructions if-else peuvent être problématiques lorsqu’elles sont utilisées à mauvais escient. Ils peuvent (étonnamment) devenir difficiles à lire et provoquer des erreurs inattendues. Lorsque les développeurs créent des instructions if-else profondément imbriquées, elles peuvent devenir difficiles à lire et impossibles à maintenir, ce qui rend le code médiocre.

De nombreux programmeurs peuvent se demander : « Devrions-nous éviter les instructions if-else ? La réponse courte est non, nous ne devrions pas le faire. Les déclarations if-else ne sont pas fausses et constituent un excellent moyen de tester des expressions et d’éliminer une certaine lisibilité. Ils doivent être utilisés pour des cas d’utilisation simples.

De nombreux développeurs JavaScript ignorent qu’il existe un modèle de code fantastique pour écrire du code conditionnel : la correspondance de modèles. Il s’agit d’un modèle de code qui nous aide à résoudre bon nombre de nos problèmes lorsqu’un branchement conditionnel est requis. Ne vous inquiétez pas du terme « branchement conditionnel » : cela peut paraître compliqué, mais ce n’est pas le cas.

Apprenons-en davantage sur le branchement conditionnel, la correspondance de modèles et comment cela peut nous aider à écrire du code avec moins de lignes et plus facile à lire.

Correspondance de motifs

La correspondance de modèles est un type de branchement conditionnel, qui est un mécanisme de programmation qui nous permet d’exécuter des morceaux de code spécifiques basés sur l’évaluation de conditions. Cela nous permettra de spécifier une situation et d’exécuter différentes parties de code selon que l’état est vrai ou faux.

« Eh bien, je peux le faire avec des instructions if-else ou switch », pensez-vous peut-être, et vous avez raison ! Ce sont des instructions faciles à utiliser, ce qui en fait un outil précieux et efficace pour les développeurs. Le problème est que lorsque nous devons évaluer des conditions complexes, ce n’est pas une bonne idée. C’est là que la correspondance de modèles peut nous aider.

La correspondance de motifs consiste à vérifier si une valeur donnée a la forme définie par un motif. Cela implique de comparer une valeur à un modèle et, si une correspondance est trouvée, une action est effectuée, comme renvoyer une valeur ou exécuter un bloc de code.

Apprenons par l’exemple. Imaginez que nous allons recevoir un objet, et que cet objet possède une propriété appelée « type ». Le type la propriété peut avoir plusieurs valeurs telles que idle,
loading, done, error, invalidetc. Gérer tout cela dans une instruction if-else peut devenir plus difficile à mesure que notre propriété change de valeur et que nous devons gérer plus de cas, n’est-ce pas ?

Un développeur débutant résoudrait ce problème en utilisant une instruction if-else comme celle-ci :

type DataType = {
  type: "idle" | "loading" | "done" | "error" | "invalid";
};

const obj: DataType = {
  type: "idle"
};

if (obj.type === "idle") {
  // ...
} else if (obj.type === "loading") {
  // ...
} else if (obj.type === "done") {
  // ...
} else if (obj.type === "error") {
  // ...
} else if (obj.type === "invalid") {
  // ...
}

Ce code est difficile à lire et devient de plus en plus complexe avec le temps. Si nous ajoutons davantage de contrôles à notre relevé, nous risquons de nous retrouver avec un énorme gâchis. Considérez à quel point il serait difficile de gérer si nous devions créer des avis imbriqués dans chaque vérification.

Résoudre ce problème avec la correspondance de modèles devient beaucoup trop simple ! Malheureusement, la correspondance de modèles n’est pas encore une fonctionnalité de JavaScript/TypeScript ; Il y a un Proposition TC39 pour ajouter une correspondance de modèle à la spécification ECMAScript. Cependant, il faudra peut-être attendre quelques années avant que nous puissions l’utiliser dans notre code.

Bien que la correspondance de modèles ne soit pas une fonctionnalité de JavaScript, nous pouvons utiliser certains packages open source, dont le meilleur est modèle ts. Cette bibliothèque TypeScript nous permet de faire correspondre des modèles dans de nombreuses structures de données différentes avec une API expressive, une prise en charge de la vérification de l’exhaustivité, garantissant que nous correspondons à tous les cas possibles, et tout cela dans une petite taille de bundle (seulement 1,7 Ko).

Utiliser ts-pattern est simple ; tout ce que nous avons à faire est d’importer la fonction de correspondance pour chacun with que nous avons. Nous devons transmettre un modèle (le modèle par rapport auquel nous voulons que notre valeur soit vérifiée) et un gestionnaire (une fonction qui sera déclenchée au cas où nous aurions une correspondance). Voici un exemple utilisant le modèle ts :

import { match } from "ts-pattern";

type Result = {
  type: "idle" | "loading" | "done" | "error" | "invalid";
};

const result: Result = { type: "error" };

match(result)
  .with({ type: "idle" }, () => console.log("idle"))
  .with({ type: "error" }, () => console.log("error"))
  .with({ type: "done" }, () => console.log("error"))
  .exhaustive();

Le exhaustive la fonction est l’un des meilleurs aspects du modèle ts. Cette fonction est chargée d’exécuter l’expression de correspondance de modèle et de renvoyer le résultat. Cela nous permet également de vérifier l’exhaustivité, en nous assurant que nous n’avons ignoré aucun cas possible dans notre valeur d’entrée. Ce niveau de sécurité supplémentaire est très utile car l’oubli d’un cas est un problème courant, notamment dans une base de code en évolution.

Nous n’avons pas testé tous les cas possibles dans notre exemple, c’est pourquoi TypeScript nous avertit. Corrigeons ce problème en vérifiant tous les cas possibles et en renvoyant un simple console.log pour chacun :

import { match } from "ts-pattern";

type Result = {
  type: "idle" | "loading" | "done" | "error" | "invalid";
};

const result: Result = { type: "error" };

match(result)
  .with({ type: "idle" }, () => console.log("idle"))
  .with({ type: "loading" }, () => console.log("loading"))
  .with({ type: "done" }, () => console.log("done"))
  .with({ type: "error" }, () => console.log("error"))
  .with({ type: "invalid" }, () => console.log("invalid"))
  .exhaustive();

Semblable à default sur les instructions switch, nous pouvons utiliser le otherwise fonction qui prend une fonction de gestionnaire renvoyant une valeur par défaut. Si nous ne voulons utiliser aucune de ces fonctions, nous pouvons simplement utiliser run à la place (ce n’est pas sûr et peut générer une erreur d’exécution si aucune branche ne correspond à votre valeur d’entrée).

Conclusion

La correspondance de modèles peut améliorer notre code et faciliter sa maintenance et son débogage. Il s’agit d’un modèle de code précieux que nous pouvons utiliser quotidiennement pour faciliter notre travail et créer de meilleures applications. La possibilité d’utiliser la correspondance de modèles dans TypeScript avec modèle ts est fantastique. Nous pouvons combiner le meilleur des deux mondes : l’inférence de type et la clarté et la concision du code.




Source link