typeof null

David Herman dherman at mozilla.com
Thu May 10 01:27:25 PDT 2012

On May 10, 2012, at 1:05 AM, Brandon Benvie wrote:

> On this tangent, I personally almost always mean "isArrayish" in this very common situation. That is, indexed with a length such that almost all Array.prototype methods would work on it out of the box. The number of arrayish interfaces provided by host environments has continued to grow. It's the epitome of generic, easily extended, usable, and efficient interfaces. Sometimes duck typing goes from "walks like a duck" to "is a vertebrate and is a bird and can fly and is found in sub-tropical areas and walks like a duck and quacks like a duck and can mate with ducks (offspring optional)".

IMO, abstract structural interfaces (duck types) and type testing don't mix very well. That is, duck typing works smoothest if you don't explicitly *ask* if something's a duck, you just document "I expect a duck here. It's your responsibility to provide me a sufficiently duck-like value."

If you want an interface that overloads a duck type with other types, e.g., one that expects either an arrayish or a string or a number, you have a couple options. You can make the arrayish the catchall case:

    function f(x) {
        switch (typeof x) {
          case "string":
            // do the string thing
          case "number":
            // do the number thing
            // do the arrayish thing

Or you can require the programmer to provide an explicit tag in another way. For example, you can have them tag the value with an object property:

    f({ name: "gray" })
    f({ hex: 0x080808 })
    f({ rgb: [127, 127, 127] })

> The following is the shortest check I can think of to accomplish this goal accurately. It isn't guaranteed to work with sparse collections but that are rare aside from built-in arrays themselves.

I'm not a fan of this approach. When you start say "those are rare" what you're saying is that there's a fuzzy boundary between the different kinds of things you accept. Either you don't really know what that boundary is, which is an invitation to bugs, or the boundary is complicated enough that your clients will be likely to be confused about it even if you document it very carefully.

> function isIndexed(o){
>   return Boolean(o) && hasOwn(o, 'length') && hasOwn(o, o.length - 1);
> }

If you overload, say, the types object and arrayish in your interface, then any time an object happens to have a length property and an n - 1 property it'll get unexpectedly categorized in the arrayish bucket. For example:

    var stringConstants = makeDict();
    stringConstants.length = "length;
    stringConstants.NaN = "NaN";
    isIndexed(stringConstants) // true

IMO it's better to keep the tests used for distinguishing between different types of input simple and obvious. For duck types, there's no straightforward test you can do, so it's better to wrap a duck type in a container that's easily testable if you want to overload it with other types and explicitly test for that case.


More information about the es-discuss mailing list