checking for typeof error in JS
Javascriptnode.jsJavascript 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.
> 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 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 */