Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Свои классы ошибок

Встроенного 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 или ваших классов-наследников.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.