add polyfill for Error.isError

This commit is contained in:
Hazelnoot 2025-11-11 20:14:44 -05:00
parent 5f50f51426
commit 9534bacbf5

View file

@ -0,0 +1,75 @@
/*
* SPDX-FileCopyrightText: hazelnoot and other Sharkey contributors
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { types } from 'node:util';
const hasDOMException = Reflect.has(globalThis, 'DOMException');
const hasErrorIsError = Reflect.has(globalThis.Error, 'isError');
/**
* Polyfill for https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/isError
*/
export const isError: IsErrorFunc = hasErrorIsError ? Error.isError : isErrorPolyfill;
/**
* Returns true if error is an instance of Error, false otherwise.
* More robust than instanceof.
*/
export type IsErrorFunc = (error: unknown) => error is Error;
export function isErrorPolyfill(error: unknown): error is Error {
// These are the fastest checks, so run them first
if (isErrorByInstance(error)) {
return true;
}
// Errors must be a non-null object
if (typeof(error) !== 'object' || error == null) {
return false;
}
// jest, and maybe a few other edge cases
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/species
if ('constructor' in error && isErrorByInstance(error.constructor[Symbol.species])) {
return true;
}
// If it looks like a duck and quacks like a duck...
if ('name' in error && typeof(error.name) === 'string') {
if ('message' in error && typeof(error.message) === 'string') {
if (!('stack' in error) || typeof(error.stack) === 'string' || typeof(error.stack) === 'undefined') {
return true;
}
}
}
// Guess it's not :(
return false;
}
function isErrorByInstance(error: unknown): boolean {
// It must be a non-null object
if (typeof(error) !== 'object' || error == null) {
return false;
}
// An actual instance, nice
if (error instanceof Error) {
return true;
}
// DOMException is an Error, just without the prototype chain
if (hasDOMException && error instanceof DOMException) {
return true;
}
// Realm fuckery
if (types.isNativeError(error)) {
return true;
}
return false;
}