检查JS中的typeof错误

Ale*_*lls 116 javascript node.js

在JS中,似乎无法检查传递给函数的参数是否实际上是"错误"类型或错误实例.

例如,这是无效的:

typeof err === 'error'

因为只有6种可能的类型(以字符串的形式):

typeof运算符将类型信息作为字符串返回.typeof返回有六个可能的值:

"number","string","boolean","object","function"和"undefined".

MSDN

但是,如果我有一个这样的简单用例怎么办:

function errorHandler(err) {

    if (typeof err === 'error') {
        throw err;
    }
    else {
        console.error('Unexpectedly, no error was passed to error handler. But here is the message:',err);
    }
}
Run Code Online (Sandbox Code Playgroud)

那么确定参数是否是Error实例的最佳方法是什么?

instanceof任何帮助的运营商?

Tro*_*ott 201

您可以使用该instanceof运算符.

var myError = new Error('foo');
myError instanceof Error // true
var myString = "Whatever";
myString instanceof Error // false
Run Code Online (Sandbox Code Playgroud)

  • @AurélienRibon 它与 `ReferenceError` 实例一起工作得很好。您正在检查全局“ReferenceError”对象。试试这个: `try { foo } catch (e) { console.log(e instanceof Error) }` 它记录 `true`。如果您出于某种原因尝试检查全局 `ReferenceError` 对象,可以使用 `Error.isPrototypeOf(ReferenceError)` (2认同)
  • 您可以尝试 `const error = (err instanceof Error || err instanceof TypeError) ?err : new Error(err.message ? err.message : err);` (2认同)

Ale*_*lls 20

我问原来的问题 - @ Trott的回答肯定是最好的.

但是,由于JS是一种动态语言,并且存在如此多的JS运行时环境,因此instanceof当跨越iframe等边界时,运算符尤其会在前端开发中失败.请参阅:https: //github.com/mrdoob/three.js/issues/5886

如果您对鸭子打字没问题,这应该是好的:

let isError = function(e){
 return e && e.stack && e.message;
}
Run Code Online (Sandbox Code Playgroud)

我个人更喜欢静态类型语言,但如果你使用的是动态语言,最好采用动态语言,而不是强迫它表现得像静态类型语言.

如果你想要更精确一点,你可以这样做:

   let isError = function(e){
     return e && e.stack && e.message && typeof e.stack === 'string' 
            && typeof e.message === 'string';
    }
Run Code Online (Sandbox Code Playgroud)

  • 在编写实用程序函数或库时,我更喜欢这个版本.它不会将用户限制在一个特定的全局上下文中,也可以正确处理来自JSON的反序列化错误. (3认同)

Zuh*_*aha 19

TypeScript 解决方案

您可以定义用户定义的类型保护,只需定义一个返回类型为类型谓词的函数

您可以像这样检查变量是否错误

const isError = (err: unknown): err is Error => err instanceof Error;
Run Code Online (Sandbox Code Playgroud)

然后在 try catch 中验证像这样

try {
  login(username, password);
} catch (err) {
  if (isError(err)) {
  console.log(err.message);
}
Run Code Online (Sandbox Code Playgroud)


hev*_*ev1 10

您可以使用Object.prototype.toString它轻松检查对象是否为Error,这也适用于不同的帧。

function isError(obj){
    return Object.prototype.toString.call(obj) === "[object Error]";
}
Run Code Online (Sandbox Code Playgroud)

function isError(obj){
    return Object.prototype.toString.call(obj) === "[object Error]";
}
Run Code Online (Sandbox Code Playgroud)

此行为由 ECMAScript 语言规范保证。

Object.prototype.toString

当调用 toString 方法时,采取以下步骤:

  1. 如果 this 值未定义,则返回“[object Undefined]”。
  2. 如果 this 值为空,则返回“[object Null]”。
  3. 让 O 成为调用 ToObject 并将 this 值作为参数传递的结果。
  4. 令 class 为 O 的 [[Class]] 内部属性的值。
  5. 返回字符串值,该值是连接三个字符串“[object”、class 和“]”的结果。

错误实例的属性

Error 实例从 Error 原型对象继承属性,它们的[[Class]]内部属性值为“Error”。错误实例没有特殊属性。

  • @亚伦那不是真的。我用 ECMAScript 语言规范的摘录编辑了我的答案。 (2认同)
  • 这是缺点最少(没有?)的最佳解决方案。 (2认同)

小智 6

var myError = new Error('foo');
myError instanceof Error // true
var myString = "Whatever";
myString instanceof Error // false
Run Code Online (Sandbox Code Playgroud)

唯一的问题是

myError instanceof Object // true
Run Code Online (Sandbox Code Playgroud)

替代方法是使用构造函数属性。

myError.constructor === Object // false
myError.constructor === String // false
myError.constructor === Boolean // false
myError.constructor === Symbol // false
myError.constructor === Function // false
myError.constructor === Error // true
Run Code Online (Sandbox Code Playgroud)

尽管应注意,此匹配非常具体,例如:

myError.constructor === TypeError // false
Run Code Online (Sandbox Code Playgroud)

  • 我不确定我是否明白这一点,TBH (4认同)

小智 5

对于那些正在寻找某种“官方”方式的人(就像我一样),这是MDN 的建议

try {
  myRoutine();
} catch (e) {
  if (e instanceof RangeError) {
    // statements to handle this very common expected error
  } else {
    throw e;  // re-throw the error unchanged
  }
}
Run Code Online (Sandbox Code Playgroud)