Erreurs personnalisées en JavaScript
JavaScript permet de créer ses propres types d'erreurs en étendant la classe Error intégrée, pour une gestion plus précise et détaillée des erreurs.
Erreurs personnalisées en JavaScript
JavaScript vous permet de créer vos propres types d'erreurs en étendant la classe intégrée Error. Une erreur personnalisée est simplement une classe qui hérite de Error (ou d'un autre type d'erreur) et qui porte un name significatif ainsi que toute donnée supplémentaire requise par la situation.
Cette page explique pourquoi vous voudriez utiliser des erreurs personnalisées, comment les définir correctement, comment distinguer les types d'erreurs avec instanceof, comment attacher du contexte (codes de statut, noms de champs, le cause original), et comment organiser une hiérarchie d'erreurs pour une application réelle.
Pourquoi créer des erreurs personnalisées ?
Lancer un simple new Error("...") fonctionne, mais cela ne donne à l'appelant qu'une chaîne de caractères à inspecter. Les erreurs personnalisées résolvent trois problèmes :
- Gestion basée sur le type. Avec
instanceof ValidationError, vous pouvez réagir à un type d'échec précis sans analyser le texte du message, ce qui est fragile et dépendant de la locale. - Contexte supplémentaire. Une classe personnalisée peut transporter des champs structurés — un
statusCodeHTTP, lefieldconcerné, une indication de nouvelle tentative — au lieu de tout entasser dans le message. - Hiérarchies claires. Une classe de base commune (par exemple
AppError) permet à un gestionnaire de haut niveau d'intercepter toutes les erreurs de votre application en un seulinstanceof, tout en laissant le code interne lancer des sous-types précis.
Si vous avez besoin d'apprendre d'abord les mécaniques de lancement/interception, lisez Gestion des erreurs : try...catch. Les erreurs personnalisées s'appuient directement sur l'héritage de classes et l'extension des classes intégrées.
Les bases de l'extension de la classe Error
Pour créer une erreur personnalisée, vous extend la classe Error. La nouvelle classe hérite de message, stack et toString() d'Error, et vous y ajoutez ce dont vous avez besoin.
Créer une classe d'erreur personnalisée
Voici le schéma minimal :
class ValidationError extends Error {
constructor(message) {
super(message); // Pass the message to the Error constructor (sets this.message)
this.name = "ValidationError"; // Override the default name "Error"
}
}Deux détails sont importants :
super(message)doit être appelé en premier. Dans un constructeur de sous-classe, vous ne pouvez pas utiliserthisavant d'avoir appelésuper(). Le constructeur d'Errordéfinitthis.messageet capture la trace de la pile d'appels.- Définissez
this.name. Sans cela, l'erreur apparaît comme"Error"dans les messages et danstoString(). Définirnamerend les journaux et le motifswitch (error.name)lisibles.
Vous pouvez également voir Object.setPrototypeOf(this, new.target.prototype) dans certains exemples. Avec les transpileurs modernes et les classes natives, c'est généralement inutile, mais cela ne nuit pas et garantit que instanceof fonctionne même lorsque le code est compilé vers ES5 ou partagé entre des contextes différents (iframes/workers). Les exemples ci-dessous le conservent par sécurité.
Une fois créée, l'erreur se comporte comme n'importe quelle autre :
const e = new ValidationError("bad input");
e.name; // "ValidationError"
e instanceof Error; // true — it is still a real Error
e.toString(); // "ValidationError: bad input"Utiliser des erreurs personnalisées
Une fois que vous avez défini une erreur personnalisée, vous pouvez la lancer dans votre application comme n'importe quelle erreur standard :
Dans cet exemple, un e-mail est validé par rapport à une expression régulière. Si la validation échoue, une ValidationError est lancée. Cette erreur est ensuite interceptée dans le bloc try...catch, et si elle est une instance de ValidationError, un message spécifique est affiché dans la console.
Gérer plusieurs types d'erreurs personnalisées
Vous pourriez vouloir créer différents types d'erreurs pour différentes parties de votre application. Voici comment gérer plusieurs erreurs personnalisées :
Cette organisation permet une gestion distincte des différents types d'erreurs, rendant l'application plus robuste et plus facile à déboguer.
Préférez instanceof à la comparaison de chaînes error.name quand vous le pouvez : instanceof correspond également aux sous-classes, donc il résiste mieux au refactoring.
Construire une hiérarchie d'erreurs avec une classe de base
Dans les applications réelles, il est utile de donner à toutes vos erreurs un ancêtre commun. Un gestionnaire de haut niveau peut alors intercepter chaque erreur « attendue » de l'application en un seul endroit, tout en laissant le code plus profond lancer des sous-types précis. L'option cause (ES2022) permet à une erreur de haut niveau d'encapsuler l'erreur de bas niveau qui l'a déclenchée, préservant l'originale pour le débogage.
Ici, this.name = this.constructor.name évite de devoir répéter le nom dans chaque sous-classe, et le seul contrôle instanceof AppError capture NotFoundError, ConflictError, et tout futur sous-type.
Gestion avancée des erreurs personnalisées en JavaScript
En s'appuyant sur les bases, nous pouvons appliquer les erreurs personnalisées à des scénarios plus complexes comme les opérations asynchrones et les cas spécifiques à la logique métier.
Exemple 1 : Gestion des erreurs API personnalisées
Cet exemple montre comment créer et utiliser une erreur personnalisée pour gérer les problèmes de requêtes API, comme lorsqu'une ressource demandée est introuvable ou que le serveur renvoie une erreur. Le flux async/await présenté ici s'associe à la gestion des erreurs avec les promesses.
Explication
- Classe ApiError : Cette classe personnalisée capture les erreurs spécifiques aux API, en stockant le code de statut HTTP avec un message personnalisé.
- Fonction fetchData : Tente de récupérer des données depuis une URL fournie. Si la réponse n'est pas réussie, elle lance une
ApiErroravec un message détaillé et le code de statut. - Gestion des erreurs : Les erreurs sont interceptées et traitées de manière appropriée. Les erreurs liées aux API sont journalisées avec des informations détaillées, tandis que les erreurs inattendues sont également interceptées et journalisées.
Exemple 2 : Gestion des erreurs de validation personnalisées
Utilisez cet exemple pour gérer les erreurs liées à la validation des données, comme la vérification des entrées utilisateur.
Explication
- Classe ValidationError : Une classe d'erreur personnalisée qui aide à identifier quel champ spécifique des données d'entrée a échoué à la vérification de validation.
- Fonction validateUser : Vérifie la validité des données utilisateur. Si les données ne satisfont pas certains critères, elle lance une
ValidationError. - Gestion des erreurs : Intercepte les erreurs de validation et les journalise avec des informations détaillées. Les autres types d'erreurs sont également gérés séparément.
Bonnes pratiques et pièges à éviter
- Appelez toujours
super(message)en premier, avant de toucher àthis. - Définissez
namepour que les journaux ettoString()soient lisibles ;this.name = this.constructor.namele fait une seule fois pour toute une hiérarchie. - Préférez
instanceofaux comparaisonserror.name— il correspond également aux sous-classes. - Relancez ce que vous ne reconnaissez pas. Un
catchqui avale tout (catch (e) {}) masque de vrais bogues. Gérez vos types connus et faitesthrow errorpour le reste, comme le font les exemples. - Utilisez
causepour encapsuler, pas pour remplacer. Quand vous interceptez une erreur de bas niveau et lancez une erreur de haut niveau, passez{ cause: original }pour que la trace de pile et la cause racine soient préservées. - Ne sous-classez pas
Errorpour contrôler le flux. Les erreurs sont faites pour les conditions exceptionnelles, pas pour les branchements normaux.
Conclusion
Créer des classes d'erreurs personnalisées en JavaScript en étendant la classe Error est une technique puissante pour gérer des types d'erreurs spécifiques de manière plus granulaire. Elle améliore la clarté et la maintenabilité de la gestion des erreurs dans votre code, vous permettant de fournir des retours et des actions plus précis selon les différentes conditions d'erreur. Cette méthode aide non seulement au débogage, mais améliore également la fiabilité de vos applications en garantissant que chaque type d'erreur est intercepté et traité de manière appropriée.