Please describe what the rule should do:
This rule would report number literals that immediately lose precision at runtime when converted to a JS Number (due to 64-bit floating-point rounding).
What category of rule is this? (place an "X" next to just one item)
[x] Warns about a potential error (problem)
Provide 2-3 code examples that this rule will warn about:
// invalid
const largeConstant1 = 1234567890123456789;
const largeConstant2 = 1.234567890123456789e19;
largeConstant1 and largeConstant2 will actually end up with a Number of 1123456789012345676800, because the mathematical value 1234567890123456789 is not precisely representable as a JS Number. The use of the digits 89 at the end of the literal are an attempt by the programmer to provide extra precision, but this extra precision doesn't appear at runtime, so the code probably contains a bug.
// invalid
const longDecimal1 = 1.234567890123456789
Similarly, longDecimal1 will end up with a Number value of 1.2345678901234567, effectively dropping the digits 89. The use of the trailing 89 is potentially confusing and probably a bug.
The rule uses significant digits in order to determine the "precision" of a literal. As a result, there are a few cases where the rule would consider a literal to be valid despite the fact that the literal is not precisely representable as a Number. For example, the following examples would be considered valid:
// valid
const shortDecimal1 = 0.11;
const largeConstant3 = 1e23;
const largeConstant4 = 100000000000000000000000;
Although the literal 0.11 gets converted to a mathematical value of 0.11000000000000000056..., the literal 0.11 is a correct approximation of that mathematical value to two significant digits. As a result, the use of the literal 0.11 is probably not a bug.
Similarly, although largeConstant3 and largeConstant4 get converted to a mathematical value of 99999999999999991611392, 1e23 and 100000000000000000000000 are both correct approximations of that mathematical value to one significant digit. As a result, the usage of these literals is probably not a bug.
The choice to not report an error for these cases is the main difference between this proposal and #8447.
Note that the rule would report an error for a literal like 100000000000000000000000.0 (with a decimal point and a zero at the end), because that literal contains 25 significant digits rather than one significant digit, and the literal is not a correct approximation of that mathematical value to 25 significant digits.
The above rules also apply to other representations of number literals (binary, hex, and octal), although those literal representations only support integers. However, the rule would not report an error for BigInt literals, because BigInt literals don't have precision loss.
I considered always reporting an error for imprecise binary/hex/octal literals (without looking at significant digits) because large binary/hex/octal literals are more often used to represent exact values (e.g. memory addresses) rather than approximate measurements. However, I decided to keep the behavior consistent to minimize false positives (e.g. to allow it to be added to eslint:recommended in the future).
Why should this rule be included in ESLint (instead of a plugin)?
This rule would identify bugs resulting from a potentially-confusing aspect of the language, with very few false positives.
For an example of a bug like this, see tc39/proposal-bigint#170. (The code in that example uses the experimental BigInt proposal, but fundamentally the footgun exists independent of the BigInt proposal.)
Are you willing to submit a pull request to implement this rule?
Yes
Please describe what the rule should do:
This rule would report number literals that immediately lose precision at runtime when converted to a JS
Number(due to 64-bit floating-point rounding).What category of rule is this? (place an "X" next to just one item)
[x] Warns about a potential error (problem)
Provide 2-3 code examples that this rule will warn about:
largeConstant1andlargeConstant2will actually end up with aNumberof1123456789012345676800, because the mathematical value 1234567890123456789 is not precisely representable as a JSNumber. The use of the digits89at the end of the literal are an attempt by the programmer to provide extra precision, but this extra precision doesn't appear at runtime, so the code probably contains a bug.Similarly,
longDecimal1will end up with aNumbervalue of 1.2345678901234567, effectively dropping the digits89. The use of the trailing89is potentially confusing and probably a bug.The rule uses significant digits in order to determine the "precision" of a literal. As a result, there are a few cases where the rule would consider a literal to be valid despite the fact that the literal is not precisely representable as a
Number. For example, the following examples would be considered valid:Although the literal
0.11gets converted to a mathematical value of 0.11000000000000000056..., the literal0.11is a correct approximation of that mathematical value to two significant digits. As a result, the use of the literal0.11is probably not a bug.Similarly, although
largeConstant3andlargeConstant4get converted to a mathematical value of 99999999999999991611392,1e23and100000000000000000000000are both correct approximations of that mathematical value to one significant digit. As a result, the usage of these literals is probably not a bug.The choice to not report an error for these cases is the main difference between this proposal and #8447.
Note that the rule would report an error for a literal like
100000000000000000000000.0(with a decimal point and a zero at the end), because that literal contains 25 significant digits rather than one significant digit, and the literal is not a correct approximation of that mathematical value to 25 significant digits.The above rules also apply to other representations of number literals (binary, hex, and octal), although those literal representations only support integers. However, the rule would not report an error for
BigIntliterals, becauseBigIntliterals don't have precision loss.I considered always reporting an error for imprecise binary/hex/octal literals (without looking at significant digits) because large binary/hex/octal literals are more often used to represent exact values (e.g. memory addresses) rather than approximate measurements. However, I decided to keep the behavior consistent to minimize false positives (e.g. to allow it to be added to
eslint:recommendedin the future).Why should this rule be included in ESLint (instead of a plugin)?
This rule would identify bugs resulting from a potentially-confusing aspect of the language, with very few false positives.
For an example of a bug like this, see tc39/proposal-bigint#170. (The code in that example uses the experimental
BigIntproposal, but fundamentally the footgun exists independent of theBigIntproposal.)Are you willing to submit a pull request to implement this rule?
Yes