Checking for Typeof Error in Js
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...
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".
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?
11 Answers
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.
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:
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';
}
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.
When the toString method is called, the following steps are taken:
- If the this value is undefined, return "[object Undefined]".
- If the this value is null, return "[object Null]".
- Let O be the result of calling ToObject passing the this value as the argument.
- Let class be the value of the [[Class]] internal property of O.
- 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.
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
TypeScript solution
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);
}
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
}
}
You can use obj.constructor.name to check the "class" of an object
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"
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>
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'))
}
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')
}
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 */