Як розширити Error власними властивостями?
1. Основна ідея
Ти створюєш власний клас, який успадковується від Error,
і додаєш до нього потрібні властивості - наприклад: code, status, details, cause, context тощо.
2. Приклад: базова кастомна помилка
javascript
class AppError extends Error {
constructor(message, code) {
super(message); // передаємо повідомлення батьку (Error)
this.name = "AppError"; // задаємо ім'я помилки
this.code = code; // додаємо власну властивість
}
}
try {
throw new AppError("Щось пішло не так", "SERVER_ERROR");
} catch (e) {
console.log(e.name); // AppError
console.log(e.message); // Щось пішло не так
console.log(e.code); // SERVER_ERROR
console.log(e.stack); // Стек викликів
}Тепер у твоєї помилки є і стандартні властивості (message, stack), і кастомні (code).
3. Приклад: додавання HTTP-коду і контексту
Це зручно для API, особливо в NestJS / Express:
javascript
class HttpError extends Error {
constructor(message, status = 500, details = {}) {
super(message);
this.name = this.constructor.name;
this.status = status;
this.details = details;
if (Error.captureStackTrace) {
Error.captureStackTrace(this, this.constructor);
}
}
}
throw new HttpError("Користувача не знайдено", 404, { userId: 123 });При обробці помилки:
javascript
try {
throw new HttpError("Користувача не знайдено", 404, { userId: 123 });
} catch (err) {
console.log(err.name); // HttpError
console.log(err.status); // 404
console.log(err.details); // { userId: 123 }
}4. Приклад: ієрархія кастомних помилок
Можна побудувати ціле "дерево" помилок:
javascript
class AppError extends Error {
constructor(message, code) {
super(message);
this.name = this.constructor.name;
this.code = code;
Error.captureStackTrace?.(this, this.constructor);
}
}
class ValidationError extends AppError {
constructor(message, field) {
super(message, "VALIDATION_ERROR");
this.field = field;
}
}
class AuthError extends AppError {
constructor(message = "Unauthorized") {
super(message, "AUTH_ERROR");
this.status = 401;
}
}Використання:
javascript
try {
throw new ValidationError("Невірний email", "email");
} catch (err) {
if (err instanceof ValidationError) {
console.log("Помилка в полі:", err.field);
}
console.log(err.code); // VALIDATION_ERROR
}5. Приклад з cause (ES2022+)
Сучасний стандарт ECMAScript підтримує властивість cause,
щоб зберігати вихідну помилку, через яку виникла поточна.
javascript
try {
JSON.parse("invalid JSON");
} catch (parseErr) {
throw new AppError("Помилка під час розбору JSON", "PARSE_ERROR", { cause: parseErr });
}Щоб підтримувати cause, потрібно додати його в конструктор:
javascript
class AppError extends Error {
constructor(message, code, options = {}) {
super(message, options);
this.name = this.constructor.name;
this.code = code;
this.cause = options.cause;
}
}6. Приклад використання в продакшені (Express / NestJS)
javascript
app.use((err, req, res, next) => {
if (err instanceof AppError) {
res.status(err.status || 500).json({
error: err.name,
message: err.message,
code: err.code,
details: err.details,
});
} else {
res.status(500).json({ error: "InternalError", message: "Невідома помилка" });
}
});7. Навіщо розширювати Error
| Причина | Приклад |
|---|---|
| Чіткі й зрозумілі повідомлення | "Email обов'язковий" замість "Unexpected token" |
| Структура і типізація | ValidationError, AuthError, HttpError |
| Зручність логування | Можна включати code, status, details |
| Зберігання вихідної причини | через cause |
| Зручність відлагодження | Різні типи помилок легко розрізняти в catch |
Підсумок
Щоб розширити Error власними властивостями:
javascript
class MyError extends Error {
constructor(message, customProp) {
super(message);
this.name = "MyError";
this.customProp = customProp;
Error.captureStackTrace?.(this, this.constructor);
}
}І використовувати:
javascript
throw new MyError("Помилка БД", { query: "SELECT * FROM users" });Коротка відповідь
Для співбесідиPremium
Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.