-
Notifications
You must be signed in to change notification settings - Fork 12.8k
'bigint' is not comparable to 'number' with loose equality #30540
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I agree that the error message Number(1n) == 1.2 // false
1n == BigInt(1.2) // RangeError: The number 1.2 cannot be converted to a BigInt because it is not an integer
Number(BigInt(Number.MAX_SAFE_INTEGER) + 2n) == Number.MAX_SAFE_INTEGER + 2 // true
BigInt(Number.MAX_SAFE_INTEGER) + 2n == BigInt(Number.MAX_SAFE_INTEGER + 2) // false The compiler gives the same warning if you tried to compare strings and numbers: // This condition will always return 'false' since the types '"1"' and '1' have no overlap.
'1' == 1 // true The fact that // Element implicitly has an 'any' type because index expression is not of type 'number'.ts(7015)
['a', 'b', 'c']['1'] // 'b' We discussed adding |
@calebsander
The double equals operator should be thought of as a function with two |
I think it's good that the compiler gives an error in this case. In my experience, comparing values of different types is usually a mistake. If not, you can explicitly convert the number to a string or the string to a number. But I agree that the error message is misleading—perhaps for |
@calebsander |
There are lots of things which are technically valid JavaScript, but TypeScript rightly warns about them because they are usually not what the programmer meant to write. For example, you can multiply two strings in JS and they will be coerced to numbers, but TypeScript forces you to explicitly coerce them. I think this is reasonable behavior, and |
TS may rightly want to error on people using IOW, the vastly more common perspective (much to my chagrin) is that devs default to using |
The interesting thing about comparing numbers with bigints in JavaScript is that it is not implemented by coercing both operands to numbers, nor is it implemented by coercing both arguments to bigints. Instead, the exact real values are compared. Here are some examples: These values are different: > 10n**50n == 10**50
false But they become equal when coerced to numbers: > Number(10n**50n) == Number(10**50)
true These values can be compared: > 1n == 1.5
false But cannot be coerced to bigints: > BigInt(1n) == BigInt(1.5)
Uncaught:
RangeError: The number 1.5 cannot be converted to a BigInt because it is not an integer Currently, it is not possible to get this comparison semantics in TypeScript without using type assertions. I agree that |
This error makes sense for Please fix it. |
I believe (but could be wrong) that the following replicates the function compare(n: number, bi: bigint): boolean {
return Number.isInteger(n) && BigInt(n) === bi;
} Note that it's not clear that that's such a useful operation, since Number.MAX_SAFE_INTEGER + 2 == BigInt(Number.MAX_SAFE_INTEGER) + 2n; // false
Number.MAX_SAFE_INTEGER + 1.5 == BigInt(Number.MAX_SAFE_INTEGER) + 1n; // true Therefore, it may well in practice be inappropriate to compare using the function compare(n: number, bi: bigint): boolean {
return Number.isSafeInteger(n) && BigInt(n) === bi;
}
function compare(n: number, bi: bigint): boolean {
if (!Number.isSafeInteger(n)) {
throw new Error("attempted to compare unsafe number with bigint");
}
return BigInt(n) === bi;
} Providing this info not particularly to weigh in on whether the |
I don't think I agree. The problem in this example isn't at all related to BigInt or the comparison, it is just that you are leaving the range of a Number. That is a questionable thing to do whether or not BigInt is involved. By that argument you can say that |
This isn't that preposterous a conclusion 🙂! In most programming languages we do avoid exact equality comparison between floats, and use a separate integer type (or multiple) for integer operations. It's just in JS, as far as I'm aware, where it's canonical to use the mantissa of floats to represent exact integers, and so we make a habit of performing integer-like operations on floats. Anyways, the important points I was trying to make were simply:
|
TypeScript Version: 3.3.3
Search Terms: bigin == number not comparable loose equality
Code
error:
but in chrome 72.0.3626.121
and in MDN https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt

And similar issues
error:
in Chrome
Playground Link:
http://www.typescriptlang.org/play/index.html#src=1n%20%3D%3D%201
http://www.typescriptlang.org/play/index.html#src=let%20x%20%3D%20%5B1%2C%202%2C%203%5D%0D%0Ax%5B1n%5D
Related Issues:
#30655
The text was updated successfully, but these errors were encountered: