eslint-plugin-unicorn icon indicating copy to clipboard operation
eslint-plugin-unicorn copied to clipboard

Rule proposal: Number(str) over parseFloat(str)

Open jamiebuilds opened this issue 3 years ago • 11 comments

Description

In most cases, Number(string) produces better results than parseFloat(string):

Number.parseFloat("420")        // 420
Number.parseFloat("-420")       // -420
Number.parseFloat("420.69")     // 420.69
Number.parseFloat("420,69")     // 420     (NaN would have been better)
Number.parseFloat("420n")       // 420     (NaN would have been better)
Number.parseFloat("420_69")     // 420     (NaN or 42069 would have been better)
Number.parseFloat("0b1000101")  // 0       (NaN or 69 would have been better)
Number.parseFloat("0x45")       // 0       (NaN or 69 would have been better)
Number.parseFloat("")           // NaN
Number.parseFloat(" \n")        // NaN
Number("420")        // 420
Number("-420")       // -420
Number("420.69")     // 420.69
Number("420,69")     // NaN
Number("420n")       // NaN
Number("420_69")     // 42069
Number("0b1000101")  // 69
Number("0x45")       // 69
Number("")           // 0      (NaN would have been better)
Number(" \n")        // 0      (NaN would have been better)

If you want to protect against those last two cases, it's a lot easier to do it with Number() than parseFloat():

function safeParseFloat(input: string) {
	if (input.trim() === "") {
    return Number.NaN
  }
  return Number(input)
}

Fail

parseFloat(input)
Number.parseFloat(input)

Pass

N/A

Additional Info

Here is a starting place for an eslint rule: https://astexplorer.net/#/gist/1569a1b6990fa03c94c76393b2ccc6a3/5e9b8eae2e48277a76e6f3680d1001b13e1d22c3

jamiebuilds avatar Apr 03 '22 20:04 jamiebuilds

I generally also prefer Number to parseInt, as the intent is to transform a stringified number rather than extracting a number from a "maybe-compatible" string. A function like this also covers the rest of the cases:

https://github.com/refined-github/refined-github/blob/4232313404c9d4afaa711217ce539680b7e3799e/source/helpers/loose-parse-int.ts#L10

fregante avatar Apr 06 '22 15:04 fregante

Correction: Number("420_69") results in NaN today, which I find surprising and isn't noted by the spec as a difference between NumericLiteral and StringNumericLiteral, I'm going to ask TC39 about that.

Those differences are useful to note here though, there are more differences than I thought there were:

Some differences should be noted between the syntax of a StringNumericLiteral and a NumericLiteral:

I still think this is better than parseFloat(str) though, these differences are still easier to protect against if you want to.

jamiebuilds avatar Apr 08 '22 18:04 jamiebuilds

I'd like forbid Number.parseFloat(), Number.parseInt() with (radix 10).

// Bad
Number.parseFloat(foo)

// Good
Number(foo)
// Bad
Number.parseInt(foo, 10)

// Good
Number.parseInt(foo, 8)
Number(foo)
Math.round(Number(foo))
Math.floor(Number(foo))
Math.ceil(Number(foo))

fisker avatar Apr 09 '22 02:04 fisker

Sounds good to me. The closest version would be with trunc to support negative values:

  const foo = '-10.1'
- Number.parseInt(foo, 10)
+ Math.trunc(Number(foo))

Unfortunately this rule can't be auto fixed though

fregante avatar Apr 09 '22 04:04 fregante

Forgot Math.trunc().

fisker avatar Apr 09 '22 04:04 fisker

Accepted

sindresorhus avatar Apr 09 '22 04:04 sindresorhus

I'd like forbid Number.parseInt() with (radix 10).

That would become annoying if you where to use closure compiler adv mode to optimize your code example: playground

jimmywarting avatar May 08 '22 17:05 jimmywarting

I'm not sure what do you mean.

fisker avatar May 08 '22 18:05 fisker

image

See this warning message, closure compiler complains if you omit radix 10. it wants you to be explicit about it

jimmywarting avatar May 08 '22 18:05 jimmywarting

Nobody is saying anything about omit radix.

fisker avatar May 08 '22 19:05 fisker

@jimmywarting His point is that Number.parseInt(x, 10) should be replaced by Math.floor(Number(x)) or similar - not to omit the radix.

papb avatar Jun 06 '22 03:06 papb