diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index f5aed2e1d5c10..99e781e25c0c0 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -43558,19 +43558,24 @@ namespace ts {
}
function checkNumericLiteralValueSize(node: NumericLiteral) {
+ // We should test against `getTextOfNode(node)` rather than `node.text`, because `node.text` for large numeric literals can contain "."
+ // e.g. `node.text` for numeric literal `1100000000000000000000` is `1.1e21`.
+ const isFractional = getTextOfNode(node).indexOf(".") !== -1;
+ const isScientific = node.numericLiteralFlags & TokenFlags.Scientific;
+
// Scientific notation (e.g. 2e54 and 1e00000000010) can't be converted to bigint
- // Literals with 15 or fewer characters aren't long enough to reach past 2^53 - 1
// Fractional numbers (e.g. 9000000000000000.001) are inherently imprecise anyway
- if (node.numericLiteralFlags & TokenFlags.Scientific || node.text.length <= 15 || node.text.indexOf(".") !== -1) {
+ if (isFractional || isScientific) {
return;
}
- // We can't rely on the runtime to accurately store and compare extremely large numeric values
- // Even for internal use, we use getTextOfNode: https://github.com/microsoft/TypeScript/issues/33298
- // Thus, if the runtime claims a too-large number is lower than Number.MAX_SAFE_INTEGER,
- // it's likely addition operations on it will fail too
- const apparentValue = +getTextOfNode(node);
- if (apparentValue <= 2 ** 53 - 1 && apparentValue + 1 > apparentValue) {
+ // Here `node` is guaranteed to be a numeric literal representing an integer.
+ // We need to judge whether the integer `node` represents is <= 2 ** 53 - 1, which can be accomplished by comparing to `value` defined below because:
+ // 1) when `node` represents an integer <= 2 ** 53 - 1, `node.text` is its exact string representation and thus `value` precisely represents the integer.
+ // 2) otherwise, although `node.text` may be imprecise string representation, its mathematical value and consequently `value` cannot be less than 2 ** 53,
+ // thus the result of the predicate won't be affected.
+ const value = +node.text;
+ if (value <= 2 ** 53 - 1) {
return;
}
diff --git a/tests/cases/fourslash/codeFixUseBigIntLiteral2.ts b/tests/cases/fourslash/codeFixUseBigIntLiteral2.ts
new file mode 100644
index 0000000000000..e34afe3c8a7ec
--- /dev/null
+++ b/tests/cases/fourslash/codeFixUseBigIntLiteral2.ts
@@ -0,0 +1,17 @@
+///
+////1000000000000000000000; // 1e21
+////1_000_000_000_000_000_000_000; // 1e21
+////0x3635C9ADC5DEA00000; // 1e21
+////100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000; // 1e320
+////100_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000; // 1e320
+
+verify.codeFixAll({
+ fixAllDescription: ts.Diagnostics.Convert_all_to_bigint_numeric_literals.message,
+ fixId: "useBigintLiteral",
+ newFileContent:
+`1000000000000000000000n; // 1e21
+1_000_000_000_000_000_000_000n; // 1e21
+0x3635C9ADC5DEA00000n; // 1e21
+100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000n; // 1e320
+100_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000n; // 1e320`,
+});
diff --git a/tests/cases/fourslash/codeFixUseBigIntLiteralWithNumericSeparators.ts b/tests/cases/fourslash/codeFixUseBigIntLiteralWithNumericSeparators.ts
new file mode 100644
index 0000000000000..fd464765c0361
--- /dev/null
+++ b/tests/cases/fourslash/codeFixUseBigIntLiteralWithNumericSeparators.ts
@@ -0,0 +1,5 @@
+///
+////6_402_373_705_728_000; // 18! < 2 ** 53
+////0x16_BE_EC_CA_73_00_00; // 18! < 2 ** 53
+
+verify.not.codeFixAvailable("useBigintLiteral");