Type casting in JavaScript

14,822

Solution 1

Your custom constructor can just examine the typeof the arguments that it is passed and behave accordingly. This isn't technically a "cast", but rather writing code to examine the types of the arguments and then decide on the proper behavior which can include converting from one type to another.

See How to overload functions in javascript? for a much longer description of how to examine arguments sent to any function and then adjust the behavior of the function based on the type and position and presence of the arguments. This same functionality can be used to do something that is "cast" like (though we don't usually think of casting in Javascript, but rather just converting).

We could give you actual code examples if you can be more specific about what types you want to "cast" in your Point constructor.

There are some simple examples of "cast" like things:

function delay(fn, t) {
    // if t is passed as a string represeantation of a number, 
    // convert it to an actual number
    return setTimeout(fn, +t);
}

Or, a little more interesting example that can take a number of ms, a string with units at the end or an object with properties:

function delay(fn, t) {
    var typeT = typeof t, ms, matches, num, multiplier,
        suffixes = {ms: 1, sec: 1000, min: 1000 * 60, hr: 1000 * 60 * 60};
    if (typeT === "string") {
        matches = t.match(/^([\d.]+)(.+)$/);
        if (matches) {
            num = +matches[1];
            multiplier = suffixes[matches[2]];
            if (multiplier) {
                ms = num * multiplier;
            }
        }
    } else if (typeT === "number") {
        // plain number is milliseconds
        ms = t;
    } else if (typeT === "object" && t.units && t.value) {
        multiplier = suffixes[t.units];
        if (multiplier) {
           ms = t.value * multiplier;
        }            
    }
    if (ms === undefined) {
        throw new Error("Invalid time argument for delay()");
    }
    return setTimeout(fn, ms);
}


delay(myFn, "2.5hr");
delay(myFn, "25sec");
delay(myFn, 150);
delay(myFn, {units: "sec", value: 25});

Solution 2

If you are serious about type enforcing (and there is a lot of good reasons to be)... and you want to continue to use Javascript... maybe you should give a try to TypeScript

It enforces type checking and compiles down to Javascript Which gives you the option to publish the TypeScript for inline compilation...

Or if you intent a bit for your work (like me)... you can develop a project and spit-out the Javascript before uploading... in this phase you can optimize the 'thing'... pass a Linter, a Minifier and a Obfuscator... and you'll get highly optimized and a bit protected piece of code (if we are talking about client-side of course, at server side no obfuscation is advised).

Another BIG-BIG-BIG advantage (to me at least) is that you can use the best Intellitype/Intellisense/Refactor IDE (VS 2013R4 CE) which is free.

See here the last features in TypeScript... TypeScript at Build/2014 by Anders Hejlsberg (channel9)

ZEE

Share:
14,822
Matthew Layton
Author by

Matthew Layton

Passionate about programming, technology and DLT.

Updated on June 04, 2022

Comments

  • Matthew Layton
    Matthew Layton almost 2 years

    Example:

    function action(value) {
         // I want to operate on a string
         String(value)...;
    }
    

    When we pass dynamic values into JavaScript's primary types (String, Number, Boolean, Object, etc.) we can (for want of a better word) cast the value to the specified type.

    Is it possible to build this feature in custom types, and how would I go about this?

    Example of what I would like to do:

    function action(value) {
        Point(value)...;
        // Value at this point (excuse the pun) is a point
        // // *** Would like to see that intellisense is aware of the type at this point, but please don't assume this is ONLY for intellisense***
    }
    

    Is it possible to call constructor functions in this way and have the constructor function "cast" the value to an instance of itself - or does this only work for JavaScript's primary types?

  • Sebastian Nette
    Sebastian Nette almost 9 years
    Better copy it as a local variable e.g var localT = +t; to avoid overwriting arguments.
  • jfriend00
    jfriend00 almost 9 years
    @SebastianNette - there's no overwriting to be worried about here. The argument t is already local to this function so there's no need to create yet another local variable.
  • Sebastian Nette
    Sebastian Nette almost 9 years
    t = +t overwrites arguments[1] which shouldn't be done, afaik (skips internal optimizations).
  • RobG
    RobG almost 9 years
    "we don't usually think of casting in Javascript, but rather just converting". Absolutely. Variables are typeless, values have a Type (which often isn't related to the value returned by typeof). Anything returned by a constructor has a Type of Object, however that's pretty useless. Usually constructor is more informative, but unreliable.
  • jfriend00
    jfriend00 almost 9 years
    @SebastianNette - that depends upon what you're optimizing for and what optimizations the exact JS engine is capable of. Are you seriously saying that it is worth adding an extra local variable declaration in a function this simple that has no performance importance? Or, are you just applying some blanket suggestion that doesn't really have any consequence in this specific example?
  • RobG
    RobG almost 9 years
    @jfriend00—there's always return setTimeout(fn, +t). ;-)
  • Sebastian Nette
    Sebastian Nette almost 9 years
    @jfriend00 Maybe it does not affect the performance of your posted example, but it's bad practice in general. I'm not saying that your answer is wrong in any way, just that it shouldn't be done like that.
  • Katana314
    Katana314 almost 9 years
    Another useful tool for this; A function can determine whether it's being used as a constructor or a function by checking this instanceof MyFunctionName. If true, it was called as new MyFunctionName