Javascript Type Gotchas

May 1st, 2010
typeof null // -> object
null instanceof null // -> TypeError: Can't use instanceof on a non-object.
true instanceof Boolean // -> false
true == new Boolean(true) // -> true
true === new Boolean(true) // -> false

Needless to say, this is very annoying if you’re trying to be be careful with your types and just goes to show that not everything is an object in Javascript. Come back soon for my attempt at a solution.

8 responses

  1. Collin Donahue-Oponski comments:

    You had me going for a few minutes… and now I understand the difference between the typeof and instanceof operators. :)

    In javascript, a “type” is different from a “class” (the object it is an instance of). So “typeof” will only return whether it is a number, boolean, string, or object. The “instanceof” operator is meant to be used on objects, to figure out what kind of object it is. So…

    typeof null
    // returns “object” because this variable is technically a null object
    null instanceof null
    // well, “null” isn’t an object type (i.e. an type you defined with a constructor)
    // I think what we meant was:
    null instanceof Object
    // returns false, because null is not an instance -> it is the lack of an instance
    true instanceof Boolean
    // returns false, because true is not an instance of an Object, it is a primitive type
    // That explains the last two examples too.

    Thanks for the lesson!

  2. Peter comments:

    Yep, you’ve basically got it Collin.

    However, there are no such things as classes in Javascript. Rather, instanceof tells you whether the left-hand side object is in the right-hand side object’s prototype chain. This is why (new String) instanceof String == true and (new String) instanceof Object == true: both String and Object are in new String‘s prototype chain. Granted, the same would be true if String were a subclass of Object in a class-based inheritance system, but remember that Javascript uses a prototype-based inheritance system and there can and often are subtle differences.

    When you use the new operator on a function (say String) in Javascript, it is essentially the same as String.call({}). That is, the String function is being called with an empty object as its this value. This this (excuse the pun) functionality means that you can have something akin to mixins. String.call(Number.call({})) should give you an object with both string and number methods. I haven’t tested this, so I can’t promise it works.

    So, returning to your conclusions from the examples, your explanations are spot on except that null really isn’t an object. I believe it’s a mistake in Javascript to return "object" from typeof null. Instead, I believe it is a primitive, not an object, and should return null.

    The solution I was hinting at, and still need to blog about, is typed.js, a better, ‘replacement’ type system for Javascript. It will give you consistent, rational type information. For instance, null is always a NullType in my type system.

  3. Peter van der Heijden comments:

    This seems to be relevant, it implements a strong type system in javascript:

    http://sourceforge.net/projects/jtypesystem/files/

    From the documentation:

    test = FT(TString, TString, TString, TArray,
    function(x,y,z){
    return new Array(x,y,z);
    });
    /* Ok */
    test(‘x’,'y’,'z’);
    /* Not ok */
    test(1,’x',’z');

  4. Peter comments:

    Thanks, Peter, I hadn’t see that library. However, I think my (incomplete) typed.js library is a little nicer:

    var test = T.typedFunction(
      {x: T.StringType, y: T.StringType, z: T.StringType},
      T.ArrayStringType,
      function(x, y, z) {
        return [x, y, z];
      }
    );
    test('x', 'y', 'z') // -> ['x', 'y', 'z']
    test(1, 'x', 'z') // -> Error: Parameter x does not satisfy type condition of type String with condition function condition(obj) { return T.is(obj, this.type); }

    Of course they’re quite similar, so your mileage may vary. I guess mine is a bit more verbose, but things like named parameters mean that my error messages are quite nice.

    You’ll notice that the error talks about type conditions because typed functions in my system can actually specify not just the simple type but rather the conditions based upon it, such as all sub-types of String, such as if you wrote your own RichString extension to String. The README has more about type conditions and implicit conversions (an implicit conversion is being done from the StringType types I provided to type conditions which test for simple equality with the type).

  5. Peter comments:

    Cool, they look really the same, but I like your named parameters more. You also doing recursive type checking. (From a quick glance of your code). Yours is much more advanced. Catching errors were a problem. But you seem to have found a elegant solution.

    I wrote mine to make working with higher order functions easier. It was a hack to make the typesystem of javascript stronger. I like to write my code in a functional style.

    Good work and thank for sharing. If I used it in a project and extend it, I will leave you a message. Cheers.

  6. Peter comments:

    Thanks, Peter. You’re right that typed.js does do recursive type-checking. However, it was a quick hack to make arrays with subtypes work. I’ve been thinking about how to revisit it to make any type of collection work, whether based on generic objects or otherwise organized.

    For example, I’d like to figure out whether multiple type parameters can be supported in an elegant way. I already use an array for type parameters but I haven’t yet figured out how to check each type parameter without requiring the object or its type object to hand its parts off to the checker. I’d like to avoid messing with Array, Object, and other standard parts of Javascript.

  7. Peter comments:

    It would be interesting to implement a static typechecker for javascript. I am working at a project for which we are developing a framework inspired by reactive programming in javascript. Because the maintainability suffered under the amount of callbacks. We separated the output to the outside world (the calling of a function, which accepts a callback) from the input from the outside world (the result, which comes from the callback). And the processing functions between the inputs and the outputs should be pure. As consequence of this, concurrency arises naturally.

    Types become more and more important in the framework.

    Static typechecking would be very handy. But dynamic type checking with good error messages is a big step forward.

  8. Peter comments:

    I’ve talked to some fellow Scala programmers about whether you could do this using Scala. At the simplest you can use Scala objects which represent Javascript code and can be converted to Javascript (such as Lift’s) but even cooler would be a DSL (and probably compiler plugin) which would let you program Javascript but actually have it be correct, statically-typed Scala behind the scenes. People tell me it’s possible…

Comments are now closed