Home > javascript > ‘typeof’ considered useless – or how to write robust type checks

‘typeof’ considered useless – or how to write robust type checks

In JavaScript it is incredibly hard to do robust type checks. The buildin “typeof” operator is meant to return the type of an expression.

typeof 12; // "number"
typeof "juhu"; //"string"

This look promising but in reality it is rarely useful because none of the buildin data types can be reliably detected by “typeof”. According to the ECMAScript specification typeof can return the following values:

Type Result
Undefined “undefined”
Null “object”
Boolean “boolean”
Number “number”
String “string”
Object (native and doesn’t implement [[Call]]) “object”
Object (native and implements [[Call]]) “function”

Lets examine the possible results of typeof.

  1. Types of “null” and “undefined”

    The type “object” of “null” values is most of the time pretty useless. The type “undefined” for undefined values however does make some sense but its more intuitive and faster to do an identity check against the value “undefined”.

    var undef; // value is undefined
    typeof undef == "undefined"; // true
    undef === undefined; // true
    
    var nullValue = null;
    typeof nullValue; // "object"
    nullValue === null; // true
    
  2. “string”, “boolean” and “number” types

    There are two ways to create a string, boolean or number in JavaScript. First by using a the literal notation and second by instantiating a string, boolean or number instance. Variables created by either of these ways behave exactly the same except that values created using the new statement are typeof “object”.

    typeof "juhu"; // "string"
    typeof new String("juhu"); // "object"
    
    typeof 123; // "number"
    typeof new Number(123); // "object"
    
    typeof 123; // "number"
    typeof new Number(123); // "object"
    

    A more robust check for these types could add an additional instanceof check.

    var value = new String("juhu");
    typeof value == "string" || value instanceof String; // true
    
  3. The “function” type

    Now functions should be simple. According to the spec should everything, which is callable should be typeof “function”. In reality this is true for all browsers except Safari/WebKit. In Safari regular expressions are considered to be typeof “function” as well. This is probably a browser bug but nonetheless makes it problematic to use typeof to detect functions .

    typeof (function() {}); // "function"
    typeof /abc/g; // "object" in IE, Firefox and Opera - "function" in Safari
    

    So instanceof checks are the better alternative.

    (function() {}) instanceof Function; // true
    (/abc/g) instanceof Function; // false in all browsers
    
  4. Detecting Arrays

    Even though arrays are native JavaScript types, the typeof statement does not support an “array” value. All arrays are typeof “object”. In my opinion this is an inconsistency in the language spec. The most common way to check for arrays is to the instanceof operator.

    typeof [1, 2, 3]; // "object"
    [1, 2, 3] instanceof Array; // true
    

BUT instanceof is Harmful

So it looks like instanceof is almost always the better alternative to typeof. This is true as long as it is guaranteed that variables are always created in the main window and never in a frame or a popup window. As kangax explains in his recent post:

The problems arise when it comes to scripting in multi-frame DOM environments. In a nutshell, Array objects created within one iframe do not share [[Prototype]]’s with arrays created within another iframe. Their constructors are different objects and so both instanceof and constructor checks fail.

Fortunately kangax comes with a nice solution to this problem. He has discovered that the “toString” method of the buildin JavaScript object reveals the internal class of a value.

function getClass(object) {
    return Object.prototype.toString.call(object).slice(8, -1);
}

This solution does not only solve the cross document issues in detecting arrays it does also solve all the problems with the typeof operator.

Value Class Type
“juhu” String string
new String(“juhu”) String object
1.2 Number number
new Number(1.2) Number object
true Boolean boolean
new Boolean(true) Boolean object
new Date() Date object
new Error() Error object
[1,2,3] Array object
new Array(1, 2, 3) Array object
new Function(“”) Function function
/abc/g RegExp object (function in Safari)
new RegExp(“abc”, “g”) RegExp object (function in Safari)
{} Object object
new Object() Object object

My prediction is that we’ll see many JavaScript frameworks switching to this kind of type checks. Dean Edwards already announced to use it in the next version of base2 in the comments of kangax post and of course the qooxdoo team will take a close look at it as well.

Update: jQuery already uses this technique since November 2008 for the “isArray” and “isFunction” functions.

Update #2: Ajaxian picked up the topic as well.

Categories: javascript Tags: , ,
  1. January 11, 2009 at 8:53 pm

    Looks realy interessting! Do you think this could make its way to the qooxdoo framework? Could be interessting for the current implementation of the inspector.

  2. admin
    January 11, 2009 at 9:01 pm

    Yes I think we can and should make use of this in qooxdoo.

  3. January 11, 2009 at 11:25 pm

    As the native toString might be limited to these 9 types a map lookup may be faster than the slice. Especially by many uses. Especially would like this in the type checks of the property system in qooxdoo.

    • January 12, 2009 at 9:17 am

      Absolutely. I have a general getClass method in mind, which uses a map lookup instead of the slice and a couple of isArray, isString, … functions, which compare to the full string. Similar to the solution in jQuery (see link in the article).

  1. March 20, 2009 at 7:38 pm
  2. September 19, 2009 at 2:26 pm

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: