Careeroza
Custom Error Classes
Extending Error
Custom error classes carry extra data (an HTTP status, an error code) and can be told apart with instanceof. Set name so logs show the right class.
Example
class AppError extends Error {
constructor(public readonly code: string, message: string, public readonly status = 500) {
super(message);
this.name = new.target.name;
}
}
class NotFoundError extends AppError {
constructor(entity: string, id: string | number) {
super("NOT_FOUND", `${entity} ${id} not found`, 404);
}
}
class ValidationError extends AppError {
constructor(public readonly fields: Record<string, string>) {
super("VALIDATION", "Invalid input", 400);
}
}
const errors: Error[] = [new NotFoundError("Product", 42), new ValidationError({ price: "must be > 0" }), new Error("boom")];
for (const e of errors) {
if (e instanceof ValidationError) console.log(e.status, e.name, e.fields);
else if (e instanceof AppError) console.log(e.status, e.name, e.message);
else console.log(500, e.name, e.message);
}Output
404 NotFoundError Product 42 not found
400 ValidationError { price: 'must be > 0' }
500 Error boomError cause
Example
ES2022 added cause to wrap a low-level error inside a meaningful one without losing the original.
function readConfig(text: string): { port: number } {
try {
return JSON.parse(text);
} catch (e) {
throw new Error("Config file is invalid", { cause: e });
}
}
try {
readConfig("{port: 3000");
} catch (e) {
if (e instanceof Error) {
console.log(e.message);
console.log("cause:", e.cause instanceof SyntaxError ? "SyntaxError" : e.cause);
}
}Output
Config file is invalid cause: SyntaxError