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

Чому змінна в catch має тип unknown і як правильно обробити помилку?

У JavaScript throw може кинути що завгодно - не лише Error, а й рядок, число, об'єкт чи undefined. Сторонні бібліотеки й старий код справді так роблять. Тому TypeScript не може гарантувати, що в catch прийде Error.

З strict (опція useUnknownInCatchVariables) змінна в catch має тип unknown:

try {
  await saveOrder(order);
} catch (error) {
  console.log(error.message);   // помилка: 'error' is of type 'unknown'
}

Звуження перед використанням:

try {
  await saveOrder(order);
} catch (error) {
  if (error instanceof ValidationError) {
    showFieldErrors(error.errors);
  } else if (error instanceof Error) {
    showToast(error.message);
  } else {
    showToast('Невідома помилка');
    report(error);
  }
}

Допоміжна функція для повідомлення:

function errorMessage(error: unknown): string {
  if (error instanceof Error) return error.message;
  if (typeof error === 'string') return error;
  return 'Невідома помилка';
}

Чому не catch (error: any): це повертає стару небезпечну поведінку - error.response.data.message компілюється й падає з TypeError, якщо помилка мережева й response немає. Явна анотація catch (error: Error) не дозволена - TypeScript не може цього гарантувати.

Пастки з instanceof:

  • помилки з іншого вікна (iframe) чи іншої копії бібліотеки в збірці не проходять instanceof - для них перевіряють name чи наявність полів;
  • власні класи помилок мають правильно наслідувати Error (class HttpError extends Error) і задавати name.

Помилки з fetch: fetch не кидає винятку на 404 чи 500 - лише на мережеві помилки. Перевірку response.ok і перетворення на власну помилку (HttpError зі статусом) робить ваш API-клієнт - тоді в catch вона розпізнається через instanceof.

Відхилені проміси - пастка: на параметр колбеку .catch((error) => ...) опція useUnknownInCatchVariables не поширюється, і він має тип any. Його варто явно анотувати: .catch((error: unknown) => ...) - а правило лінтера @typescript-eslint/use-unknown-in-catch-callback-variable нагадає про це. З async/await і try/catch проблеми немає.

Докладніше в документації: TypeScript 4.4: unknown у catch

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