Свои классы ошибок
Встроенного Error хватает, чтобы сообщить о проблеме, но не всегда понятно, какая именно это проблема. Неверный email, отсутствующий товар и сбой сети требуют разной реакции. Свои классы ошибок позволяют отличать их друг от друга.
Класс ошибки
Ошибка — это объект класса Error, поэтому свою ошибку создают наследованием. Свойство name задают таким же, как имя класса, — тогда его видно в сообщениях:
class ValidationError extends Error {
name = 'ValidationError';
}
const error = new ValidationError('Неверный email');
console.log(error.name); // ValidationError
console.log(error.message); // Неверный emailКонструктор писать не нужно: текст сообщения принимает и сохраняет конструктор родителя Error.
Различение ошибок
Оператор instanceof проверяет, к какому классу относится ошибка. Так в одном catch можно по-разному обработать разные проблемы:
class ValidationError extends Error {
name = 'ValidationError';
}
function checkAge(age) {
if (age < 0) {
throw new ValidationError('Возраст не может быть отрицательным');
}
return age;
}
try {
checkAge(-5);
} catch (error) {
if (error instanceof ValidationError) {
console.log(`Проверьте данные: ${error.message}`); // Проверьте данные: Возраст не может быть отрицательным
}
}Дополнительные данные
В свою ошибку можно добавить свойства — например, имя поля формы, в котором ошибка. Для этого пишут конструктор и сначала вызывают super(message):
class ValidationError extends Error {
name = 'ValidationError';
constructor(field, message) {
super(message);
this.field = field;
}
}
const error = new ValidationError('email', 'Неверный формат');
console.log(`${error.field}: ${error.message}`); // email: Неверный форматПовторный выброс
Если catch получил ошибку, которую не умеет обработать, её выбрасывают снова через throw. Тогда она дойдёт до кода, который знает, что с ней делать:
class ValidationError extends Error {
name = 'ValidationError';
}
function handle(action) {
try {
action();
} catch (error) {
if (error instanceof ValidationError) {
return 'Ошибка в данных';
}
throw error;
}
}
try {
handle(() => {
throw new TypeError('Неожиданный сбой');
});
} catch (error) {
console.log(error.name); // TypeError
}Причина ошибки
Иногда одна ошибка вызвана другой. Вторым аргументом Error можно передать объект с полем cause — исходную ошибку. Так при разборе проблемы видна вся цепочка:
try {
try {
JSON.parse('{ сломано }');
} catch (error) {
throw new Error('Не удалось загрузить настройки', { cause: error });
}
} catch (error) {
console.log(error.message); // Не удалось загрузить настройки
console.log(error.cause.name); // SyntaxError
}Частая ошибка
Выбросить можно любое значение, даже строку, но делать так не стоит. У строки нет name, message и стека вызовов — по ней не понять, где возникла проблема:
try {
throw 'Что-то пошло не так';
} catch (error) {
console.log(error.message); // undefined
}Всегда выбрасывайте объекты Error или ваших классов-наследников.