Airbrake Blog

JavaScript Error Handling - X Is (Not) Y TypeError

Written by Frances Banks | Jun 1, 2017 2:00:31 PM

Next up in our JavaScript Error Handling series we'll be going over the X Is (Not) Y TypeError. The X Is (Not) Y TypeError is just one of the many TypeErrors we'll take a look at in this error handling series, which typically deal with accessing values that are not the appropriate data types. In this case, the X Is (Not) Y TypeError is a rather general-purpose error that is thrown most often when methods expect a certain data type as an argument, but are passed a different data type instead.

In this article we'll explore the X Is (Not) Y TypeError in more detail, seeing where it sits within the JavaScript Exception hierarchy and also looking at a few simple code examples that show how X Is (Not) Y TypeErrors are commonly thrown. Let's get to it!

The Technical Rundown

  • All JavaScript error objects are descendants of the Error object, or an inherited object therein.
  • The TypeError object is inherited from the Error object.
  • The X Is (Not) Y TypeError is a descendant of TypeError object.

When Should You Use It?

The X Is (Not) Y TypeError can occur when dealing with most any data type in JavaScript, though it's most common when using undefined or null types. We won't go into the full details of these special types in this article, but if you'd like more information check out the details in our Null or Undefined Has No Properties article earlier in this series.

The X Is (Not) Y TypeError comes in many forms, hence the relaxed naming convention found in the Mozilla Developer Network documentation. Simply put, this error occurs during a few different situations:

  • The target object is null when it shouldn't be.
  • The target object is undefined when it shouldn't be.
  • The target object is not of a specific expected type (Object, Symbol, null, etc).

Let's start with the first two causes, when the target object is null or undefined yet it's expected to be something else. To see this in action we have little example snippet with a title variable that we've declared as undefined. We then try to extract a substring of title using the String.prototype.substring() method and output the result to the console:

var printError = function(error, explicit) {
console.log(`[${explicit ? 'EXPLICIT' : 'INEXPLICIT'}] ${error.name}: ${error.message}`);
}

try {
// Initialize title as undefined
var title = undefined;
// Try to get substring of undefined title
console.log(title.substring(1));
} catch (e) {
if (e instanceof TypeError) {
printError(e, true);
} else {
printError(e, false);
}
}

The problem here is that title is undefined, which doesn't have a property or method named substring. Our Chrome output indicates as much in the error message, while Firefox behaves differently and gives us the X Is (Not) Y TypeError format:

// CHROME
[EXPLICIT] TypeError: Cannot read property 'substring' of undefined

// FIREFOX
[EXPLICIT] TypeError: title is undefined

Let's try null instead of undefined in the same scenario:

try {
// Initialize title as null
var title = null;
// Try to get substring of null title
console.log(title.substring(1));
} catch (e) {
if (e instanceof TypeError) {
printError(e, true);
} else {
printError(e, false);
}
}

Unsurprisingly, this also throws a X Is (Not) Y TypeError that looks very similar:

// CHROME
[EXPLICIT] TypeError: Cannot read property 'substring' of null

// FIREFOX
[EXPLICIT] TypeError: title is null

We also saw that, outside of manipulating null and undefined objects that should be other types, we can also get a X Is (Not) Y TypeError when trying to directly manipulate certain object prototypes by passing in incompatible argument types. For example, here we've created a simple String title variable and assigned it a value. We then want to create an Object type from our title variable:

try {
// Initialize title as string
var title = 'The Hobbit';
// Try to create object from string title
console.log(Object.create(title));
} catch (e) {
if (e instanceof TypeError) {
printError(e, true);
} else {
printError(e, false);
}
}

The problem arises because the Object.create() method expects a prototype Object to be passed in as the first argument, instead of something like a String, as in this case. This results in another X Is (Not) Y TypeError being thrown our way:

// CHROME
[EXPLICIT] TypeError: Object prototype may only be an Object or null: The Hobbit

// FIREFOX
[EXPLICIT] TypeError: title is not an object or null

As is often the case, Chrome tends to report more accurate and human-readable error messages, so it's explicitly telling us that the passed argument equal to The Hobbit should actually be an Object or a null, whereas Firefox sticks with the X Is (Not) Y TypeError format.

To dive even deeper into understanding how your applications deal with JavaScript Errors, check out the revolutionary Airbrake JavaScript error tracking tool for real-time alerts and instantaneous insight into what went wrong with your JavaScript code.