JS에서 typeof 오류 확인


153

JS에서는 함수에 전달 된 인수가 실제로 'error'유형인지 또는 Error 인스턴스인지 확인할 수 없습니다.

예를 들어, 이것은 유효하지 않습니다 :

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는 오류가 프레임이나 다른 창의 코드에서 비롯된 경우 문제가되지 않습니까? 이 경우 다른 프로토 타입 오류 개체가 있으며 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에 대한 참조를 유지하면 obj.hasOwnProperty()오류가 발생하는 것과 같은 객체 프로토 타입 fns를 호출하려고하면 오류가 발생합니다!)
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객체에 대해서도 거짓을 반환 합니다. 이 경우 가장 쉬운 방법은 오리 타이핑입니다.

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

그러나 오류가 아닌 개체 stackmessage속성 이있는 경우 오리 입력시 오 탐지가 발생할 수 있습니다 .


1
@ AurélienRibon ReferenceError인스턴스 와 함께 잘 작동 합니다. 전역 ReferenceError객체를 확인하고 있습니다. 이것을 시도하십시오 : try { foo } catch (e) { console.log(e instanceof Error) }그것은 기록 true합니다. ReferenceError어떤 이유로 전역 객체 를 검사하려는 경우 다음을 사용할 수 있습니다.Error.isPrototypeOf(ReferenceError)
Trott

1
@ Aurélien 리본 나는 그것을 확인하는 상황을 생각해내는 데 어려움을 겪고 있지만 절대적으로 정확하지만 유스 케이스의 유효성보다 상상력의 부족에 대해 더 많이 말할 수 있습니다).
Trott

하하, 그 녀석들에 대해 유감스럽게 생각합니다. 모든 ReferenceError인스턴스가의 인스턴스가 아닌 이상한 오류가 발생했습니다 Error. 이는 vm.runInNewContext()모든 표준 프로토 타입이 재정의 된 노드 호출로 인한 것 입니다. 모든 결과는 표준 객체의 인스턴스가 아닙니다. 나는 이것에 대해 SO에서 찾고, 그리고 :이 스레드에 빠졌다
오렐리 Ribon

1
시도해보십시오const error = (err instanceof Error || err instanceof TypeError) ? err : new Error(err.message ? err.message : err);
Aamir Afridi

instanceof특정 유형의 오류가 있는지 어떻게 확인 합니까?
oldboy

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

감사합니다. 예, 많은 경우에 오류처럼 보이면 오류처럼 취급 할 수 있습니다. 어떤 경우에는 오리 타이핑이 완전히 허용 가능하고 어떤 경우에는 전혀 허용되지 않습니다.이 경우 완벽하게 괜찮습니다.
Alexander Mills

디버거를 사용하여 디버깅을 수행했으며 스택 및 메시지는 실제로 오류 인스턴스에서 두 가지 비 네이티브 속성 인 것으로 보입니다.
Alexander Mills

1
@Trott instanceof경우 에 따라 운영자가 실패하는 것에 대해 알고 싶을 수도 있습니다 . 링크 된 기사를 참조하십시오.
Alexander Mills

1
이것은 실제로 가장 단순하므로 다른 유형의 오류 (예 Error: ReferenceError, ...) 와 함께 작동합니다 . 그리고 내 환경 instanceof에서 많은 상황에서 비참하게 실패합니다.
Alexis Wilke

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

이것의 유일한 문제는

myError instanceof Object // true

이에 대한 대안은 constructor 속성을 사용하는 것입니다.

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

위의 줄은 객체의 클래스 이름 인 "Error"를 기록합니다. 클래스가 "name"이라는 속성을 사용하지 않는 경우 자바 스크립트의 모든 클래스와 함께 사용할 수 있습니다.


이것은 코드를 축소하고 오류 서브 클래스를 사용할 때 신뢰할 수 없습니다
felixfbecker

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.