checking for typeof error in JS

Javascriptnode.js

Javascript Problem Overview


In JS it doesn't seem possible to check if an argument passed to a function is actually of the type 'error' or an instance of Error.

For example, this is not valid:

typeof err === 'error'

since there are only 6 possible types (in the form of strings):

The typeof operator returns type information as a string. There are six possible values that typeof returns:

> "number", "string", "boolean", "object", "function" and "undefined".

[MSDN][1]

But what if I have a simple use case like this:

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

so what is the best way to determine if an argument is an instance of Error?

is the instanceof operator of any help?

[1]: https://msdn.microsoft.com/library/259s7zc1%28v=vs.94%29.aspx "MSDN JS typeof info"

Javascript Solutions


Solution 1 - Javascript

You can use the instanceof operator (but see caveat below!).

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

The above won't work if the error was thrown in a different window/frame/iframe than where the check is happening. In that case, the instanceof Error check will return false, even for an Error object. In that case, the easiest approach is duck-typing.

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

However, duck-typing may produce false positives if you have non-error objects that contain stack and message properties.

Solution 2 - Javascript

I asked the original question - @Trott's answer is surely the best.

However with JS being a dynamic language and with there being so many JS runtime environments, the instanceof operator can fail especially in front-end development when crossing boundaries such as iframes. See: https://github.com/mrdoob/three.js/issues/5886

If you are ok with duck typing, this should be good:

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

I personally prefer statically typed languages, but if you are using a dynamic language, it's best to embrace a dynamic language for what it is, rather than force it to behave like a statically typed language.

if you wanted to get a little more precise, you could do this:

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

Solution 3 - Javascript

You can use Object.prototype.toString to easily check if an object is an Error, which will work for different frames as well.

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([]));

This behavior is guaranteed by the ECMAScript Language Specification.

Object.prototype.toString:

> When the toString method is called, the following steps are taken: > 1. If the this value is undefined, return "[object Undefined]". > 2. If the this value is null, return "[object Null]". > 3. Let O be the result of calling ToObject passing the this value as the argument. > 4. Let class be the value of the [[Class]] internal property of O. > 5. Return the String value that is the result of concatenating the three Strings "[object ", class, and "]".

Properties of Error Instances:

> Error instances inherit properties from the Error prototype object and their [[Class]] internal property value is "Error". Error instances have no special properties.

Solution 4 - Javascript

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

Only problem with this is

myError instanceof Object // true

An alternative to this would be to use the constructor property.

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

Although it should be noted that this match is very specific, for example:

myError.constructor === TypeError // false

Solution 5 - Javascript

TypeScript solution

You can define a user-defined type guard, simply need to define a function whose return type is a type predicate

You can check if a variable is error like this

const isError = (err: unknown): err is Error => err instanceof Error;

then inside try catch validate that like this

try {
  login(username, password);
} catch (err) {
  if (isError(err)) {
  console.log(err.message);
}

Solution 6 - Javascript

You can use obj.constructor.name to check the "class" of an object https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name#Function_names_in_classes

For Example

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

The above line will log "Error" which is the class name of the object. This could be used with any classes in javascript, if the class is not using a property that goes by the name "name"

Solution 7 - Javascript

For those, who're looking for some 'official' way (like I did), this is what MDN recommends:

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

Solution 8 - Javascript

Thanks @Trott for your code, I just used the same code and added with a real time working example for the benefit of others.

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

Solution 9 - Javascript

Or use this for different types of errors

function isError(val) {
  return (!!val && typeof val === 'object')
    && ((Object.prototype.toString.call(val) === '[object Error]')
      || (typeof val.message === 'string' && typeof val.name === 'string'))
}

Solution 10 - Javascript

Just use the error.name

function _err(type = false) {
	if(type) {
		throw new TypeError('Oh crap!')
	}
	throw new Error('Oh crap!')
}

try {
	_err(true)
} catch (error) {
	console.log(typeof error.name, error.name, error.name === 'TypeError')
}

try {
	_err()
} catch (error) {
	console.log(typeof error.name, error.name, error.name === 'Error')
}

Solution 11 - Javascript

You can take the answer from @iota a bit further and check the test object's internal [[Prototype]] property via getPrototypeOf() or the deprecated __proto__ property.

If the object is an error, it inherits from Error.prototype. So maybe something like this:

// the object you want to check 
const objectToCheck = new Error();

// current way
console.log(Object.getPrototypeOf(objectToCheck) === Error.prototype);  /* true*/

// deprecated way
console.log(objectToCheck.__proto__ === Error.prototype);  /* true */

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAlexander MillsView Question on Stackoverflow
Solution 1 - JavascriptTrottView Answer on Stackoverflow
Solution 2 - JavascriptAlexander MillsView Answer on Stackoverflow
Solution 3 - JavascriptUnmitigatedView Answer on Stackoverflow
Solution 4 - JavascriptTomView Answer on Stackoverflow
Solution 5 - JavascriptZuhair TahaView Answer on Stackoverflow
Solution 6 - Javascriptpersistent_poltergeistView Answer on Stackoverflow
Solution 7 - Javascriptanatoly uView Answer on Stackoverflow
Solution 8 - JavascriptZabi BaigView Answer on Stackoverflow
Solution 9 - JavascriptChrisView Answer on Stackoverflow
Solution 10 - JavascriptThiago LagdenView Answer on Stackoverflow
Solution 11 - JavascriptdoWhileTrueView Answer on Stackoverflow