Un aspect du développement JavaScript avec lequel de nombreux développeurs se débattent est le traitement des valeurs facultatives. Quelles sont les meilleures stratégies pour minimiser les erreurs causées par des valeurs qui pourraient être null
, undefined
ou non initialisées lors de l’exécution?
Certaines langues ont des possibilités intégrées pour ces circonstances. Dans certains langages à typage statique, vous pouvez dire que null
et undefined
sont des valeurs illégales, et laissez votre langage de programmation lancer une erreur de type au moment de la compilation , mais même dans ces langages, cela ne peut « t empêcher les entrées nulles de circuler dans le programme lors de l’exécution.
Pour mieux gérer ce problème, nous devons comprendre d’où ces valeurs peuvent provenir. Ici sont parmi les sources les plus courantes:
- Saisie utilisateur
- Enregistrements de base de données / réseau
- État non initialisé
- Fonctions qui pourraient ne rien renvoyer
Lorsque vous avez affaire à des entrées utilisateur, la validation est la première et la meilleure ligne de défense. Je compte souvent sur des validateurs de schéma pour m’aider dans ce travail. Par exemple, consultez react -jsonschema-form.
Enregistrements hydratants à partir des entrées
Je passe toujours les entrées que je reçois du réseau, de la base de données ou des entrées utilisateur via une fonction d’hydratation. Par exemple, j’utiliserai créateurs d’actions redux capables de gérer
valeurs pour hydrater les enregistrements des utilisateurs:
const setUser = ({ name = "Anonymous", avatar = "anon.png" } = {}) => ({
type: setUser.type,
payload: {
name,
avatar
}
});
setUser.type = "userReducer/setUser";
Parfois, vous devrez afficher différentes choses en fonction de l’état actuel des données. S’il est possible d’afficher une page avant que toutes les données ne soient initialisées, vous pouvez vous retrouver dans cette situation. Par exemple, lorsque vous affichez des soldes monétaires à un utilisateur, vous pouvez accidentellement afficher un solde de 0 USD avant le chargement des données. J’ai vu cela bouleversé les utilisateurs à plusieurs reprises. Vous pouvez créer des types de données personnalisés qui génèrent différentes sorties en fonction de l’état actuel:
Le code ci-dessus est une machine à états qui rend impossible l’affichage des états invalides. Lorsque vous créez le solde pour la première fois, il sera défini sur un état uninitialized
. Si vous essayez d’afficher un solde alors que l’état est uninitialized
, vous obtiendrez toujours une valeur d’espace réservé (« --
« ) à la place.
Pour changer cela, vous devez définir explicitement une valeur en appelant la méthode .set
ou le raccourci setBalance
nous avons défini ci-dessous l’usine createBalance
.
L’état lui-même est encapsulé pour le protéger des interférences extérieures afin de s’assurer que les autres fonctions ne peuvent pas le saisir et le définir à un état invalide.
Remarque: Si vous vous demandez pourquoi nous utilisons des chaînes au lieu de nombres pour cela, c’est parce que je représente les types d’argent avec de grandes chaînes numériques avec beaucoup de précision décimale pour éviter les erreurs d’arrondi et représenter avec précision les valeurs des transactions de crypto-monnaie, qui peuvent avoir une précision décimale arbitraire significative.
Si vous ‘ re utilisant l’architecture Redux ou Redux, vous pouvez déclarer des machines d’état avec Redu x-DSM.
Évitez de créer des valeurs nulles et indéfinies
Dans vos propres fonctions, vous pouvez éviter de créer null
ou undefined
pour commencer. Il y a plusieurs façons de le faire intégrées à JavaScript qui me viennent à l’esprit. Voir ci-dessous.
Évitez les valeurs nulles
Je ne crée jamais explicitement de valeurs null
en JavaScript, car je n’ai jamais vraiment vu l’utilité d’avoir deux valeurs différentes valeurs primitives qui signifient essentiellement «cette valeur n’existe pas».
Depuis 2015, JavaScript prend en charge les valeurs par défaut qui sont remplies lorsque vous ne fournissez pas de valeur pour l’argument ou la propriété en question. Ces valeurs par défaut ne fonctionnent pas pour les valeurs null
. C’est généralement un bug, d’après mon expérience. Pour éviter ce piège, n’utilisez pas null
dans JavaScript.
Si vous voulez des cas spéciaux pour les valeurs non initialisées ou vides, les machines à états sont un meilleur choix. Voir ci-dessus.
Nouvelles fonctionnalités JavaScript
Quelques fonctionnalités peuvent vous aider à gérer null
ou undefined
valeurs. Les deux sont des propositions de l’étape 3 au moment de la rédaction de cet article, mais si vous « relisez du futur, vous pourrez peut-être les utiliser.
Au moment de la rédaction de cet article, le chaînage facultatif est une proposition de l’étape 3. Cela fonctionne comme ceci:
const foo = {};
// console.log(foo.bar.baz); // throws error
console.log(foo.bar?.baz) // undefined
Nullish Coalescing Operator
Également une proposition d’étape 3 à ajouter à la spécification, « nullish coalescing operator « Est fondamentalement une manière sophistiquée de dire » opérateur de valeur de secours « . Si la valeur à gauche est undefined
ou null
, la valeur est la valeur à droite.Cela fonctionne comme ceci:
Asynchrone Soit avec Promesses
Si une fonction peut ne pas retourner avec une valeur, il peut être judicieux de l’envelopper dans un Either. Dans la programmation fonctionnelle, la monade Either est un type de données abstrait spécial qui vous permet d’attacher deux chemins de code différents: un chemin de réussite ou un chemin d’échec. JavaScript a un type de données asynchrone intégré Sither monad-ish appelé Promise. Vous pouvez l’utiliser pour créer des branches d’erreur déclaratives pour des valeurs non définies:
Vous pouvez en écrire une version synchrone si vous le souhaitez, mais je n’en ai pas beaucoup besoin. Je vais laisser cela comme un exercice pour vous. Si vous avez une bonne connaissance des foncteurs et des monades, le processus sera plus facile. Si cela vous semble intimidant, ne vous en faites pas. Utilisez simplement des promesses. Ils sont intégrés et fonctionnent très bien la plupart du temps.
Les tableaux pour Maybes
Les tableaux implémentent une méthode map
qui prend une fonction qui est appliquée à chaque élément du tableau. Si le tableau est vide, la fonction ne sera jamais appelée. En d’autres termes, les tableaux en JavaScript peuvent remplir le rôle de Maybes à partir de langages comme Haskell.
Qu’est-ce qu’un Maybe?
Un Maybe est un type de données abstrait spécial qui encapsule une valeur facultative . Le type de données prend deux formes:
- Juste – Un Peut-être qui contient une valeur
- Rien – un Peut-être sans valeur
Voici l’essentiel de l’idée:
Ceci est juste un exemple pour démontrer le concept. Vous pouvez créer toute une bibliothèque de fonctions utiles autour de maybes, en implémentant d’autres opérations comme flatMap
et flat
(par exemple, pour éviter Just(Just(value))
lorsque vous composez plusieurs fonctions renvoyant Maybe). Mais JavaScript a déjà un type de données qui implémente beaucoup de ces fonctionnalités prêtes à l’emploi, donc j’utilise généralement pour cela à la place: The Array.
Si vous voulez créer une fonction qui peut ou peut ne pas produire de résultat (en particulier s’il peut y avoir plus d’un résultat), vous pouvez avoir un bon cas d’utilisation pour renvoyer un tableau.
Je trouve le fait que map
ne sera pas appelé sur une liste vide très utile pour éviter les valeurs null
et undefined
, mais rappelez-vous, si le tableau contient les valeurs null
et undefined
, il appellera la fonction avec ces valeurs, donc si la fonction que vous exécutez pourrait produire null
ou undefined
, vous « devrez les filtrer hors de votre tableau renvoyé, comme illustré ci-dessus. Cela pourrait avoir pour effet de modifier la longueur de la collection.
Dans Haskell, il y a une fonction maybe
qui (comme ) applique une fonction à une valeur. Mais la valeur est facultative et encapsulée dans un Maybe
. Nous pouvons utiliser le type de données JavaScript « s Array
pour faire essentiellement la même chose:
maybe
prend une valeur de repli , puis une fonction à mapper sur le tableau peut-être, puis un tableau peut-être (un tableau contenant une valeur, ou rien), et renvoie soit le résultat de l’application de la fonction au contenu du tableau, soit la valeur de repli si le tableau est vide.
Pour plus de commodité, j’ai également défini une fonction toMaybeArray
, et curé la fonction maybe
pour créer c’est plus évident pour cette démonstration.
Si vous souhaitez faire quelque chose comme ça dans le code de production, j’ai créé une bibliothèque open source testée à l’unité pour le rendre plus facile. Il s’appelle Maybearray. L’avantage de Maybearray par rapport aux autres bibliothèques JavaScript Maybe est qu’il utilise des tableaux JavaScript natifs pour représenter les valeurs, vous n’avez donc pas à leur donner de traitement spécial ou à faire quoi que ce soit de spécial pour effectuer des conversions. Lorsque vous rencontrez des tableaux Maybe dans votre débogage, vous n’avez pas à vous demander « quel est ce type étrange?! » C’est juste un tableau d’une valeur ou d’un tableau vide et vous les avez vus un million de fois auparavant.
Étapes suivantes
Il y a beaucoup plus de contenu sur EricElliottJS.com, y compris beaucoup de vidéos, d’exercices, de captures d’écran enregistrées et de conseils rapides. Si vous n’êtes pas membre, c’est le moment idéal pour voir ce que vous avez manqué!