Современные способы обработки ошибок в TypeScript: от try/catch к Result¶
Традиционный try/catch в TypeScript часто приводит к "пирамидам смерти", скрытым ошибкам и сложностям с тестами. Рассмотрим 4 современных подхода: обёртки промисов, Result/Either, глобальные хэндлеры и комбинированный стек с Sentry.123
1. Обёртки над промисами (to/safeAsync)¶
Вместо try/catch вокруг каждого await — утилита, возвращающая [error, data].
Код до:
Код после:
Плюсы:
- Меньше вложенности
- Явный возврат ошибки
- Похоже на Go (
result, err)
Минусы:
- Деструктуризация
[err, data]везде - Нет типизации конкретных ошибок
- Много
if (err)проверок
Когда использовать: Быстрый рефакторинг legacy-кода.45
2. Result/Either (ошибка как значение)¶
Функции возвращают Result<T, E> — union успеха/ошибки с методами map/flatMap.
Реализация (7 строк):
Сервис без throw:
Цепочка в хуке:
Плюсы:
- Полная типобезопасность (
Result<User, UserNotFoundError>) - Линейная композиция (
flatMap) - Тестирование без моков исключений
- +200x быстрее throw в циклах
Минусы:
- Boilerplate для простых случаев
- Изменение сигнатур всех функций
- Нужны type guards для union ошибок
Когда использовать: Enterprise React/TS проекты >10k строк.678
3. Глобальные хэндлеры + минимальный try/catch¶
Один try/catch на границе (контроллер/хуки), внутри — голые throw только для багов.
Браузер (React):
Хук без локального try/catch:
Плюсы:
- Минимум boilerplate
- Автоматический stack trace + Sentry
- Совместимо с любым legacy
Минусы:
throwгде угодно — не предсказуемоunknownтип в catch- Тесты требуют
mockRejectedValue
Когда использовать: Команды с mixed skill level.9
Сравнение подходов¶
| Подход | Типобезопасность | Тестируемость | Производительность | Сложность миграции | Кодовая вложенность |
|---|---|---|---|---|---|
| try/catch | ❌ unknown | ❌ мок throw | ❌ stack trace | ✅ 0% | ❌ пирамида |
| to() обёртки | ⚠️ [Error,null] | ✅ частично | ✅ хорошо | ✅ 20% | ⚠️ много if |
| Result/Either | ✅ Result<T,E1 | E2> | ✅ идеально | ✅ отлично | ❌ 60% | ✅ линейно |
| Глобальные хэндлеры | ❌ throw | ❌ мок throw | ⚠️ нормально | ✅ 10% | ❌ скрытый поток |
Рекомендуемый стек для React/TS 2025¶
Result<T,E>для сервисов/хуковto()для быстрого парсинга/API- Sentry + ErrorBoundary на границе
- neverthrow библиотека (
npm i neverthrow)
Полный хук:
Заключение¶
Result/Either — золотой стандарт для новых TS проектов: предсказуемость + производительность. Глобальные хэндлеры + Sentry — для телеметрии и legacy. to() — промежуточный шаг миграции.
Выбор зависит от размера команды и проекта: для соло-разработки хватит to() + Sentry, для enterprise — полноценный Result с доменными ошибками.103
Бонус: готовый Result репозиторий — neverthrow или мой gist с примерами выше. Пробуй на pet-проекте!1112
-
interests.programming_error_handling ↩
-
https://dev.to/swyx/errors-are-not-exceptional-1g0b ↩
-
https://www.reddit.com/r/SoftwareEngineering/comments/1feb20n/why_do_many_prefer_error_as_value_over_exceptions/ ↩↩
-
https://brianschiller.com/blog/2025/02/07/the-best-ts-result/ ↩
-
https://dev.to/richardshaju/stop-using-try-catch-a-better-way-to-handle-errors-in-javascript-14cm ↩
-
https://dev.to/jimjja/error-handling-without-try-catch-blocks-4kok ↩
-
https://blog.dennisokeeffe.com/blog/2024-07-14-creating-a-result-type-in-typescript ↩
-
https://www.typescript-result.dev/handling-errors ↩
-
https://khalilstemmler.com/articles/enterprise-typescript-nodejs/functional-error-handling/ ↩
-
interests.programming.javascript_error_handling ↩
-
https://www.perplexity.ai/search/3678f7af-62c3-47d4-aea6-e7a6aa5065a4 ↩
-
https://www.perplexity.ai/search/04f63c72-29c3-4046-a2cc-08fd8dcb8ed0 ↩
-
https://github.com/Rayologist/Result-Type ↩
-
https://github.com/haideralsh/ts-result ↩