Historique de la question : En JavaScript, les erreurs standard sont décrites via la classe Error. Dans les grands projets TypeScript, il est important d'utiliser sa propre hiérarchie d'erreurs pour un traitement précis des situations, mais il y a des nuances avec les types, l'héritage et le comportement de 'instanceof'.
Problème : Lors de l'héritage d'Error, des difficultés peuvent survenir : le prototype est perdu, 'instanceof' fonctionne mal, les types peuvent être mal décrits, et la sérialisation conduit souvent à la perte de la trace de la pile. Sans spécification explicite des propriétés, des bugs peuvent se produire lors du traitement des erreurs.
Solution : Définir correctement les erreurs personnalisées en étendant la classe Error. Il convient de spécifier clairement le nom, de restaurer le prototype manuellement (important pour ES5 et lors de la compilation en CommonJS), et de typer les propriétés d'erreur.
Exemple de code :
class ValidationError extends Error { code: number; constructor(message: string, code: number = 400) { super(message); Object.setPrototypeOf(this, ValidationError.prototype); this.name = 'ValidationError'; this.code = code; } } function process(user: string) { if (!user) throw new ValidationError('Utilisateur requis', 401); }
Caractéristiques clés :
Pourquoi ne peut-on pas omettre l'appel à Object.setPrototypeOf(this, ...)?
Si l'on n'appelle pas Object.setPrototypeOf(this, Class.prototype), 'instanceof' ValidationError ne fonctionnera pas lors de la compilation en ES5/CommonJS ou Babel. Cela entraînera la non-capture de l'erreur dans les blocs catch ValidationError.
class CustomErr extends Error {} const err = new CustomErr('msg'); console.log(err instanceof CustomErr); // false sans setPrototypeOf
Peut-on omettre le champ name de l'erreur personnalisée ?
Si la propriété this.name n'est pas définie, la pile d'erreurs et l'affichage dans les logs seront incorrects, ce qui compliquera la recherche de la cause et la classification des erreurs.
Les erreurs doivent-elles être sérialisables, et si oui, comment ?
Les erreurs doivent être correctement sérialisées (par exemple, pour le logging ou le transfert réseau), sinon JSON.stringify(new Error()) ne renverra pas message et stack. Il convient de redéfinir la méthode toJSON.
class SerializableError extends Error { toJSON() { return { name: this.name, message: this.message, stack: this.stack }; } }
Dans le projet, nous avons simplement fait class MyError extends Error, sans restaurer le prototype. Les erreurs étaient attrapées via if (err instanceof MyError), mais cela ne fonctionnait pas, et le code passait silencieusement le traitement des situations critiques.
Avantages :
Inconvénients :
Nous avons mis en œuvre un CustomError correct, clairement défini name, code et toJSON, et les tests ont couvert le traitement de différents types d'erreurs. Dans les logs et les gestionnaires catch, la structure des erreurs est devenue claire, ce qui a réduit le temps de recherche des bugs.
Avantages :
Inconvénients :