Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Як створити власний клас помилки і навіщо властивість cause?

Власні класи помилок дають змогу розрізняти помилки за типом, а не за текстом повідомлення, і передавати додаткові дані.

class HttpError extends Error {
  constructor(response, options) {
    super(`HTTP ${response.status} для ${response.url}`, options);
    this.name = 'HttpError';
    this.status = response.status;
  }
}

class ValidationError extends Error {
  constructor(errors) {
    super('Дані не пройшли перевірку');
    this.name = 'ValidationError';
    this.errors = errors;   // { email: ['Поле обов'язкове'] }
  }
}

this.name варто задавати явно: саме воно відображається в консолі й стеку (ValidationError: Дані не пройшли перевірку). Без нього всі помилки виглядатимуть як Error.

Обробка за типом:

async function request(url, options) {
  const response = await fetch(url, options);
  if (response.status === 422) {
    throw new ValidationError((await response.json()).errors);
  }
  if (!response.ok) {
    throw new HttpError(response);
  }
  return response.json();
}

try {
  await request('/api/orders', { method: 'POST', body });
} catch (error) {
  if (error instanceof ValidationError) {
    showFieldErrors(error.errors);   // формат помилок валідації Laravel
  } else if (error instanceof HttpError && error.status === 403) {
    showError('Недостатньо прав');
  } else {
    throw error;
  }
}

cause (ES2022) - посилання на початкову помилку, що спричинила поточну. Передається другим аргументом конструктора:

try {
  config = JSON.parse(await readConfig());
} catch (error) {
  throw new Error('Не вдалося завантажити конфігурацію', { cause: error });
}

Навіщо: на вищому рівні потрібне зрозуміле повідомлення («не вдалося завантажити конфігурацію»), але без втрати технічної причини («Unexpected token } in JSON at position 42»). Раніше доводилося або губити початкову помилку, або склеювати повідомлення рядками. Тепер ланцюжок причин зберігається повністю, і DevTools та Sentry показують його.

Це аналог previous у винятках PHP (new RuntimeException('...', previous: $e)).

Що варто знати:

  • instanceof працює з класами, що наслідують Error, - у сучасних середовищах без хитрощів (раніше Babel ламав це при компіляції в ES5);
  • не варто створювати клас на кожну дрібницю - лише там, де код по-різному реагує на помилки;
  • помилки, що перетинають межі (з воркера, з postMessage, з серверу), втрачають клас - при серіалізації залишаються лише name і message. Тип доведеться відновлювати за name чи кодом.

Докладніше в документації: Error: cause

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання