Achtergrond: In JavaScript worden standaardfouten beschreven via de Error-klasse. In grote TypeScript-projecten is het belangrijk om een eigen hiërarchie van fouten te gebruiken voor nauwkeurige verwerking van situaties, maar er zijn nuances met types, erfelijkheid en het gedrag van 'instanceof'.
Probleem: Bij het erven van Error kunnen zich moeilijkheden voordoen: het prototype gaat verloren, 'instanceof' werkt niet correct, types kunnen onjuist worden beschreven, en serialisatie leidt vaak tot verlies van de stack trace. Zonder expliciete opgave van eigenschappen kunnen er bugs optreden bij het verwerken van fouten.
Oplossing: Definieer aangepaste fouten correct door de Error-klasse uit te breiden. Het is belangrijk om de naam expliciet te specificeren, het prototype handmatig te herstellen (dit is belangrijk voor ES5 en bij compilatie naar CommonJS), en de velden van de fouten te typeren.
Voorbeeldcode:
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('User required', 401); }
Belangrijke kenmerken:
Waarom mag je de aanroep van Object.setPrototypeOf(this, ...) niet overslaan?
Als je Object.setPrototypeOf(this, Class.prototype) niet aanroept, werkt 'instanceof' ValidationError niet bij compilatie naar ES5/CommonJS of Babel. Dit leidt ertoe dat catch-blokken voor ValidationError de fout niet opvangen.
class CustomErr extends Error {} const err = new CustomErr('msg'); console.log(err instanceof CustomErr); // false zonder setPrototypeOf
Kan het name-veld bij een aangepaste fout worden weggelaten?
Als je de eigenschap this.name niet instelt, zullen de stack van de fout en de weergave in logs onjuist zijn, wat het zoeken naar de oorzaak en de classificatie van fouten bemoeilijkt.
Moeten fouten serializeerbaar zijn, en zo ja, hoe?
Fouten moeten correct worden geserialized (bijvoorbeeld voor logging of netwerkoverdracht), anders geeft JSON.stringify(new Error()) geen message en stack terug. Je moet de toJSON-methode overschrijven.
class SerializableError extends Error { toJSON() { return { name: this.name, message: this.message, stack: this.stack }; } }
In een project maakten we gewoon class MyError extends Error, zonder het prototype te herstellen. Fouten werden opgevangen met if (err instanceof MyError), maar dit werkte niet, en de code liet stilletjes kritieke situaties door.
Voordelen:
Nadelen:
We implementeerden een correcte CustomError, specificeerden expliciet name, code en toJSON, en de tests dekken de verwerking van verschillende soorten fouten. In de logs en de catch-handlers werd de structuur van de fouten duidelijk, waardoor de tijd voor het zoeken naar bugs werd verminderd.
Voordelen:
Nadelen: