Error.isError()
: Лучший способ проверки типов ошибки в JavaScript
Error.isError()
в JavaScript: почему он лучше instanceof
, как решает проблемы кросс-контекстных ошибок и типизации в TypeScript.Система обработки ошибок JavaScript долгое время оставалась слепым пятном
при работе с ошибками в разных контекстах исполнения. Новый метод Error.isError()
устраняет это ограничение, предоставляя разработчикам более надёжный способ идентификации объектов ошибок.
Традиционный подход к проверке является ли значение ошибкой — это использование оператора instanceof
.
try {
// Код, который может выбросить ошибку
} catch (e) {
if (e instanceof Error) {
// Обработка ошибки
}
}
У этого подхода есть два существенных ограничения:
Ошибки из разных областей неправильно идентифицируются. Когда ошибка исходит из другой области (например, из
iframe
или модуля VM),instanceof Error
возвращаетfalse
, потому что у каждой области есть свой конструкторError
.const iframe = document.createElement('iframe');
document.body.appendChild(iframe);
const iframeError = iframe.contentWindow.Error;
// ошибка в области iframe
const crossRealmError = new iframeError('Error from iframe');
// Эта проверка не работает, хотя это явная ошибка
console.log(crossRealmError instanceof Error); // false 🔴
// Error.isError() определяет её корректно
console.log(Error.isError(crossRealmError)); // true 🟢Это может привести к тому, что ошибки обрабатываются некорректно, так как проверка
instanceof
не срабатывает.Фейковые ошибки могут пройти тест. Объекты, имеющие в цепочке прототипов
Error.prototype
, но не обладающие характеристиками ошибки, будут неверно идентифицированы как ошибки.// «Фейковая» ошибка, задав Error.prototype в цепочке прототипов
const fakeError = { message: "I'm not a real error" };
Object.setPrototypeOf(fakeError, Error.prototype);
// Ошибочно идентифицируется как Error
console.log(fakeError instanceof Error); // true 🔴
// Error.isError() корректно отклоняет её
console.log(Error.isError(fakeError)); // false 🟢
Эти проблемы могут привести к непоследовательной обработке ошибок и трудно диагностируемым багам. Новый метод Error.isError()
предлагает решение:
try {
// Код, который может выбросить ошибку
} catch (e) {
if (Error.isError(e)) {
// Уверенная обработка ошибки
}
}
Вместо проверки цепочки прототипов Error.isError()
использует более простой и надёжный подход. Используется специальный внутренний маркер (как скрытый ID тег), добавляемый к каждому настоящему объекту Error
при его создании.
Этот метод работает лучше, чем instanceof
, по двум причинам:
- Корректно идентифицирует ошибки, даже если они исходят из разных контекстов (например,
iframe
или модулей). - Отбрасывает фейковые объекты, пытающиеся притвориться ошибками, манипулируя прототипом
Считайте, его проверкой водяного знака производителя вместо, просмотра этикетки — его сложнее подделать.
Типизация Error.isError()
Один из способов типизации метода Error.isError()
в TypeScript:
try {
} catch (e: unknown) { // Код, который может выбросить ошибку
if (Error.isError(e)) { // 'e' сужается до типа Error
console.log(e.message); // Теперь она типобезопасная
} else { // Обработка исключений, не связанных с Error
console.log("Non-error was thrown:", e);
}
}