Type Checking Techniques in JavaScript Part 2 of 2

To get the most out of this article you’ll want a solid grasp of JavaScript’s data types including built-in, custom, and host objects. If you need a little refresher see Part 1.



As front-end developers today are working with larger code bases, more 3rd party frameworks, and in teams, using effective type checking techniques is critical to writing bug free code. And you know how it goes, right? Less bugs means less Jira tickets reopened, less QA regressions, less work for project leads, and happier managers.

But the JavaScript language seems to be working against us. With it’s untyped var keyword, absence of typed parameters in function signatures, and implicit type conversions, combined with the lack of a unified getType() function, our need for reliable approaches is only increased.

In this article I’ll cover three effective techniques for type checking and identify each of their advantages and disadvantages. Let’s get started.


 typeof operator

This first type checking technique is useful for checking primitives types. The typeof operator returns a string representation of the variable’s type[1].

The syntax is

typeof variable

In action

var val;
typeof val;  // returns "undefined"

val = 10000;
typeof val;  // returns "number"

val = 'woohoo';
typeof val;  // returns "string"

val = true;
typeof val;  // returns "boolean"

val = null;
typeof val;  // returns "object", an ERROR

The laughable error is typeof on a null variable returns "object" when instead it should return "null", but it’s too late to correct. Because of this we’re forced to check for null by

if(val === null) {
   ...
}

typeof is of no use for distinguishing objects.

var val = {a:1, b:2};    // creates new Object object
typeof val;              // returns "object"

val = [1,2,3];           // creates new Array object
typeof val;              // returns "object"

val = new RegExp('a+b'); // creates new RegExp object
typeof val;              // returns "object"

To muddy up the waters even more, it gives us a bonus value.

function doStuff(){}     // function declaration
typeof doStuff;          // returns "function"

But don’t be misled, functions are not their own type. They’re of the single “object” type[2]. But this "function" value is still useful. We know that invoking an unknown variable can be risky because it’ll throw a TypeError if it’s not a function. typeof provides the safeguard to know whether the variable is a function before you invoke it.

function someFunc(param) {
    if(typeof param === 'function') {
        param();
    }
}

 typeof summary

Pros Cons
Simple way to identify primitive types typeof on null variable returns "object".
Can be used as a safeguard to identify “functions” before invoking them Misleads that function is a type when it’s not
Differentiates primitive types from their object equivalent (e.g. 5 is not same as new Number(5) All object types return “object”. It doesn’t distinguish between objects, such as an Array and RegExp


 instanceof operator

This second technique is the only way to identify custom objects and can be useful for identifying built-in objects. It checks if a given object was created by a given constructor function[3].

The syntax is

object_reference instanceof ConstructorFunction

In action

// MyObj constructor function
function MyObj(){}

// create new MyObj
var myObj = new MyObj();

myObj instanceof MyObj;   // returns true
myObj instanceof RegExp;  // returns false

For better or worse, instanceof traverses up an object’s prototype chain, checking if the object in question is an instance of the given constructor function or any of it’s parent objects.

function ParentObj(){}  // parent constructor function
function ChildObj(){}   // child constructor function

 // set child to inherit from parent
ChildObj.prototype = new ParentObj;
ChildObj.prototype.constructor = ChildObj;

// instantiate instance of child
var child = new ChildObj();

// test if instance of child
child instanceof ChildObj // true

// test if instance of parent
child instanceof ParentObj // true

At times this behavior may be useful, but it’s problematic. It leaves us with no way to determine which constructor function instantiated the object within it’s inheritance chain. By this one check we don’t know if child was created by ChildObj or ParentObj.

 instanceof summary

Pros Cons
Only way to identify custom objects Must know object’s constructor function to check against
Also works for non-static built-in objects Doesn’t work for primitive types
Traverses prototype chain to check if instance of parent object (Also a negative) Can’t verify which constructor function instantiated object within inheritance chain


 Object.prototype.toString

The third type checking technique is useful for identifying built-in objects.

Whenever an object is created it’s assigned several internal properties under the hood. One of these is the [[Class]] property whose value is the kind of object it is. For built-in objects this value is the name of the object’s constructor function[5].

var array = [];        // new array's internal [[Class]] is Array
var date = new Date(); // new date's internal [[Class]] is Date

We can use this unique, read-only property for type checking. The built-in Object’s toString() method will return this internal [[Class]] property[4]. We can invoke it with our object in question using the call() method located on every Function prototype.

var arr = [1,2,3];
Object.prototype.toString.call(arr);  // returns "[object Array]"

var reg = new RegExp('a+b');
Object.prototype.toString.call(reg);  // returns "[object RegExp]"

Object.prototype.toString.call(JSON); // returns "[object JSON]"

The string format [object [[Class]]] is returned.

Interestingly, primitive types can be also identified using this approach.

var val = 10000; // primitive number
Object.prototype.toString.call(val); // returns "[object Number]"

val = 'abc';     // primitive string
Object.prototype.toString.call(val); // returns "[object String]"

val = true;      // primitive boolean
Object.prototype.toString.call(val); // returns "[object Boolean]"

val = null;      // primitive null
Object.prototype.toString.call(val); // returns "[object Null]"

val = undefined; // primitive undefined
Object.prototype.toString.call(val);//returns "[object Undefined]"

It’s worth noting custom objects always return [object Object], which isn’t very useful. Use instanceof when checking those kinds of objects. The [[Class]] property values of host (browser) objects varies greatly per browser as it isn’t specified in the language spec.

 Object.prototype.toString() summary

Pros Cons
Only way to identify all built-in objects Verbose
Normalizes primitive types and their corresponding wrapper objects (Also a negative) Does not differentiate whether a primitive or object


 Summary

In this post we identified three reliable approaches to type checking, all based on what you’re working with. Primitives are best identified using typeof with the exception of the null value. It’s checked by val === null. Object.prototype.toString is used when wanting to normalize primitive numbers, strings, booleans with their wrapper object equivalents as being the same. Built-in objects are best identified using Object.prototype.toString because it identifies types for both static and non-static built-in objects. Custom objects, which are objects defined by the developer, can only be identified using instanceof, though unfortunately there isn’t a way to distinguish whether the object was constructed by a given constructor or it’s parent object’s constructor. Host objects are best identified using Object.prototype.toString because most are static. Even so, their values vary greatly between browser implementations.

I hope there was something of value for you in this post. I’d greatly enjoy your comments or questions. Please feel free to reach out on LinkedIn.



References:

[1] - EMCAScript 5.1 spec, http://www.ecma-international.org/ecma-262/5.1/#sec-11.4.3

[2] - EMCAScript 5.1 spec, http://www.ecma-international.org/ecma-262/5.1/#sec-4.3.24

[3] - Resig, J., & Bibeault, B. (2013). Secrets of the JavaScript Ninja (p. 127). Shelter Island, NY: Manning.

[4] - EMCAScript 5.1 spec http://www.ecma-international.org/ecma-262/5.1/#sec-15.2.4.2

[5] - ECMAScript 5.1 spec http://www.ecma-international.org/ecma-262/5.1/#sec-8.6.2

 
40
Kudos
 
40
Kudos

Now read this

Rediscovering MVC and How to Write without a Framework

If you’ve paid much attention to front-end development in the last few years you’ve heard about Angular, Backbone, Ember, and other JavaScript MV* frameworks. They offer structure, bundled APIs and streamlined approaches to complex UIs,... Continue →