JSのtypeofエラーをチェックする


153

JSでは、関数に渡された引数が実際に「エラー」タイプであるか、エラーのインスタンスであるかどうかを確認することは不可能のようです。

たとえば、これは無効です。

typeof err === 'error'

可能なタイプは6つしかないため(文字列の形式):

typeof演算子は、型情報を文字列として返します。typeof返される可能性のある値は6つあります。

「数値」、「文字列」、「ブール値」、「オブジェクト」、「関数」、「未定義」。

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);
    }
}

では、引数がエラーのインスタンスであるかどうかを判断する最良の方法は何ですか?

instanceofヘルプのオペレーターは何ですか?


10
はい、使用しますerr instanceof Error
colecmc

2
@colecmcは、エラーがフレームまたは別のウィンドウのコードに起因する可能性がある場合、問題にはなりませんか?その場合、異なるプロトタイプErrorオブジェクトが存在し、instanceofは期待どおりに機能しません。(developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…を参照)
Doin

@Doin、私はそうは思いません。実際のエラーオブジェクトを検証するだけです。
colecmc

1
@ colecmc、erriframeを(たとえば)スローしたが、それを親ウィンドウに渡して処理すると、が表示されることがわかると思います(err instanceof Error) === false。これは、iframeとその親ウィンドウに異なる、異なるErrorオブジェクトプロトタイプがあるためです。同様に、obj = {};willのようなオブジェクトは、別のウィンドウで実行されている関数yeildに渡され(obj instanceof Object)===falseます。(最悪でも、IEでは、ウィンドウが破棄またはナビゲートされた後もobjへの参照を保持している場合、オブジェクトプロトタイプfnsを呼び出そうとするとobj.hasOwnProperty()エラーがスローされます!)
Doin

どのようにエラーの種類を確認しますか?すなわちエラーをcatch((err)=>{if (err === ENOENT)返しENOENT is not definedますか?
oldboy

回答:


261

instanceof演算子を使用できます(ただし、以下の警告を参照してください)。

var myError = new Error('foo');
myError instanceof Error // true
var myString = "Whatever";
myString instanceof Error // false

チェックが行われている場所とは異なるウィンドウ/フレーム/ iframeでエラーがスローされた場合、上記は機能しません。その場合、instanceof ErrorチェックはErrorオブジェクトであってもfalseを返します。その場合、最も簡単なアプローチはダックタイピングです。

if (myError && myError.stack && myError.message) {
  // it's an error, probably
}

ただし、プロパティを含むエラー以外のオブジェクトがある場合、ダックタイピングは誤検知を生成する可能性がstackありmessageます。


1
@AurélienRibon ReferenceErrorインスタンスで問題なく動作します。グローバルReferenceErrorオブジェクトをチェックしています。これを試してください:try { foo } catch (e) { console.log(e instanceof Error) }ログに記録しtrueます。ReferenceError何らかの理由でグローバルオブジェクトをチェックしようとしている場合は、次を使用できますError.isPrototypeOf(ReferenceError)
Trott

1
@AurélienRibon(ええと、ええと、「これはReferenceErrorでは機能しません」と間違っているのか、単に「これはグローバルReferenceErrorオブジェクトでは機能しません」と指摘したのかはわかりませんでした。これは間違いなく正しいですが、私はそれをチェックする状況を思い付くのに苦労していますが、それはユースケースの妥当性よりも私の想像力の欠如についてもっと言うかもしれません)。
Trott

ああ、その人たちにごめんなさい、私は私のすべてのReferenceErrorインスタンスがのインスタンスではない奇妙なエラーに閉じ込められましたError。これはvm.runInNewContext()、すべての標準プロトタイプが再定義されるinノードの呼び出しが原因でした。私の結果はすべて、標準オブジェクトのインスタンスではありませんでした。私はこれについてSOを探していて、このスレッドに陥りました:)
Aurelien Ribon

1
あなたが試すことができますconst error = (err instanceof Error || err instanceof TypeError) ? err : new Error(err.message ? err.message : err);
アーミルアフリディ2017年

instanceof特定のタイプのエラーであるかどうかをどのように確認しますか?
oldboy '30 / 10/30

25

私は元の質問をしました-@Trottの答えは確かに最高です。

ただし、JSが動的言語であり、非常に多くのJSランタイム環境があるため、instanceofオペレーターは、特にフロントエンド開発でiframeなどの境界を越えるときに失敗する可能性があります。参照:https : //github.com/mrdoob/three.js/issues/5886

あなたがアヒルのタイピングで大丈夫なら、これは良いはずです:

let isError = function(e){
 return e && e.stack && e.message;
}

私は個人的には静的型付け言語を好みますが、動的言語を使用している場合は、静的型付け言語のように動作させるのではなく、動的言語を採用することをお勧めします。

もう少し正確にしたい場合は、次のようにします。

   let isError = function(e){
     return e && e.stack && e.message && typeof e.stack === 'string' 
            && typeof e.message === 'string';
    }

3
ユーティリティ関数またはライブラリを作成するときは、このバージョンを好みます。ユーザーを特定のグローバルコンテキストに制限せず、JSONからの非シリアル化エラーも適切に処理します。
snickle 2017

ええ、多くの場合そうです、それがエラーのように見える場合、私たちはエラーのように扱うことができます。場合によっては、アヒルのタイピングが完全に受け入れられることもありますが、まったく受け入れられない場合もあります。この場合は、まったく問題ありません。
Alexander Mills

デバッガーを使用していくつかのデバッグを行いましたが、スタックとメッセージは実際には、Errorインスタンスの2つの非ネイティブプロパティであるように見えます。
Alexander Mills

1
@Trott instanceof場合によっては、オペレーターが失敗することについて知りたい場合があります。リンクされた記事を参照してください。
Alexander Mills

1
これは、異なるタイプのエラーで動作しますので、実際に最も単純である(すなわちErrorReferenceError、...)。そして私の環境ではinstanceof、多くの状況で惨めに失敗します。
Alexis Wilke、

10
var myError = new Error('foo');
myError instanceof Error // true
var myString = "Whatever";
myString instanceof Error // false

これに関する唯一の問題は

myError instanceof Object // true

これに代わる方法は、コンストラクタープロパティを使用することです。

myError.constructor === Object // false
myError.constructor === String // false
myError.constructor === Boolean // false
myError.constructor === Symbol // false
myError.constructor === Function // false
myError.constructor === Error // true

ただし、この一致は非常に具体的であることに注意してください。次に例を示します。

myError.constructor === TypeError // false

2

を使用Object.prototype.toStringして、オブジェクトがであるかどうかを簡単に確認できますError。これは、さまざまなフレームでも機能します。

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

function isError(obj){
    return Object.prototype.toString.call(obj) === "[object Error]";
}
console.log("Error:", isError(new Error));
console.log("RangeError:", isError(new RangeError));
console.log("SyntaxError:", isError(new SyntaxError));
console.log("Object:", isError({}));
console.log("Array:", isError([]));


1

obj.constructor.nameを使用して、オブジェクトの「クラス」を確認できますhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name#Function_names_in_classes

例えば

var error = new Error("ValidationError");
console.log(error.constructor.name);

上記の行は、オブジェクトのクラス名である「エラー」をログに記録します。これは、クラスが「name」という名前のプロパティを使用していない場合、JavaScriptのすべてのクラスで使用できます。


コードを縮小してエラーサブクラスを使用する場合、これは信頼できません
felixfbecker '27

1

@Trottのコードに感謝します。同じコードを使用し、他の人のためにリアルタイムで動作する例を追加しました。

<html>
<body >

<p>The **instanceof** operator returns true if the specified object is an instance of the specified object.</p>



<script>
	var myError = new Error("TypeError: Cannot set property 'innerHTML' of null"); // error type when element is not defined
	myError instanceof Error // true
	
	
	
	
	function test(){
	
	var v1 = document.getElementById("myid").innerHTML ="zunu"; // to change with this
	
	try {
		  var v1 = document.getElementById("myidd").innerHTML ="zunu"; // exception caught
		  } 
		  
	catch (e) {
		  if (e instanceof Error) {
			console.error(e.name + ': ' + e.message) // error will be displayed at browser console
		  }
  }
  finally{
		var v1 = document.getElementById("myid").innerHTML ="Text Changed to Zunu"; // finally innerHTML changed to this.
	}
	
	}
	
</script>
<p id="myid">This text will change</p>
<input type="button" onclick="test();">
</body>
</html>


0

または、これをさまざまなタイプのエラーに使用します

function isError(val) {
  return (!!val && typeof val === 'object')
    && ((Object.prototype.toString.call(val) === '[object Error]')
      || (typeof val.message === 'string' && typeof val.name === 'string'))
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.