0

I want to coerce strings to primitives whenever possible, in a way that is safe to pass any value. I'm looking for a more "native" way of doing it, instead of trying to cover all possible cases.

value("0") //0
value("1") //1
value("-1") //-1
value("3.14") //3.14
value("0x2") //2
value("1e+99") //1e+99

value("true") //true
value("false") //false
value("null") //null
value("NaN") //NaN
value("undefined") //undefined
value("Infinity") //Infinity
value("-Infinity") //-Infinity

value("") //""
value(" ") //"  "
value("foo") //"foo"
value("1 pizza") //"1 pizza"

value([]) //[]
value({}) //{}

value(0) //0
value(1) //1
value(-1) //-1
value(3.14) //3.14
value(0x2) //2
value(1e+99) //1e+99

you get the idea

function value(x){
    if(typeof x==="string"){
        if(x=="") return x;
        if(!isNaN(x)) return Number(x);
        if(x=="true") return true;
        if(x=="false") return false;
        if(x=="null") return null;
        if(x=="undefined") return undefined;
    }
    return x;
}

The major problem is that because isNaN() return "is a Number" for things like

"" empty strings
"   " blank strings
[] arrays
etc

Edit

Based on the accepted answer:

function value(x) {
    if (typeof x === "string") {
        switch (x) {
            case "true": return true;
            case "false": return false;
            case "null": return null;
            case "undefined": return void 0;
        }
        if (!isNaN(x) && !isNaN(parseFloat(x))) return +x;
    }
    return x;
}
Vitim.us
  • 20,746
  • 15
  • 92
  • 109
  • 1
    Re `if(+x==+x && !isNaN(x))`: `+x==+x` will *always* be true unless `+x` is `NaN`, consequently that check doesn't make much sense. Also, if you're going to use the unary `+` to convert to number, why not be consistent rather than calling `Number` sometimes (which does the same thing)? – T.J. Crowder Oct 24 '15 at 17:01
  • 1
    What problem are you having? – Steven Schobert Oct 24 '15 at 17:02
  • The simplest evil way of doing this is by: `return eval(x)` – Max Oct 24 '15 at 17:03
  • 1
    @MaxMastalerz: Which will blow up on `"1 pizza"`. Also, if this is user input (he said speculatively), you don't want to open the door to arbitrary code execution. – T.J. Crowder Oct 24 '15 at 17:03
  • You should probably be using `===` comparisons in there. – Pointy Oct 24 '15 at 17:03
  • I'm looking for a more elegant solution instead of trying to catch every single possible case that I cannot think of in antecipation. – Vitim.us Oct 24 '15 at 17:03
  • @Vitim.us you don't have to think of them. Just look at the spec. – Pointy Oct 24 '15 at 17:04
  • @Pointy: There's no need, he's already determined that `x` is a string, so given he's comparing to strings (except the `+x==+x` case I called out above), `==` and `===` do exactly the same thing. – T.J. Crowder Oct 24 '15 at 17:04
  • Well if not eval, there is no other short way of doing this. – Max Oct 24 '15 at 17:07

2 Answers2

1

The problem with your code is that isNaN alone can't be used to detect numeric strings properly.

For example, since +" " === 0, then isNaN(" ") === false.

Instead, I suggest using the 2nd isNumeric function of this list of testcases, taken from Validate decimal numbers in JavaScript.

function isNumeric(n) {
  return !isNaN(n) && !isNaN(parseFloat(n));
}
function value(x){
  if(typeof x !== "string") return x;
  switch(x) {
    case "true": return true;
    case "false": return false;
    case "null": return null;
    case "undefined": return void 0;
  }
  if(isNumeric(x)) return +x;
  return x;
}
Community
  • 1
  • 1
Oriol
  • 274,082
  • 63
  • 437
  • 513
0

I'll just go ahead and say what I think we're all saying in comments: There's no native way to do this that does exactly what you've outlined.

You've talked about covering all the bases, but there really aren't that many bases to cover, they're listed in the specification, and you seem to have done most of the work. Just be sure that whatever utility function you have that does this has an adequate test suite, and if you find cases you haven't covered (or new primitives are added to the spec, which is really unlikely), update the function and its tests accordingly.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875