I found myself in the situation where I wanted to convert a BigInt
value to a Number
value. Knowing that my value is a safe integer, how can I convert it?
-
4Are you referring to the Stage 3 proposal? That would be documented there.– Sebastian SimonCommented Dec 29, 2018 at 15:03
-
Nice @Xufox, thanks for the edit.– Lucio PaivaCommented Dec 29, 2018 at 15:14
4 Answers
Turns out it's as easy as passing it to the Number
constructor:
const myBigInt = BigInt(10); // `10n` also works
const myNumber = Number(myBigInt);
Of course, you should bear in mind that your BigInt value must be within [Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER] for the conversion to work properly, as stated in the question.
-
6
-
6@Mohammad see: github.com/tc39/proposal-bigint/blob/master/… Commented Dec 23, 2021 at 19:57
You can use parseInt
or Number
const large = BigInt(309);
const b = parseInt(large);
console.log(b);
const n = Number(large);
console.log(n);
-
8For performance reasons, I suggest not using
parseInt
for this. Yes, yes, according to the specs, bothparseInt
andNumber
ought to perform the conversion by converting the BigInt to a string before to a number. Nevertheless, the semantics ofparseInt
compared to the semantics ofNumber
especially in view of howBigInt(number)
yields a BigInt makes it more likely that browser vendors will apply more optimizations toNumber(bigValue)
thanparseInt(bigValue)
such that the stringification is internally skipped. Thus, I suggest usingNumber
instead ofparseInt
for performance.– Jack GCommented Feb 14, 2020 at 16:59 -
@JackGiffin please see this stackoverflow.com/questions/4090518/… where
parseInt
can be better in some cases Commented Feb 14, 2020 at 17:12 -
1I am afraid that I do not understand. I agree that
parseInt
andNumber
have different behaviors, but, for the purposes of converting a BigInt to a number, I can think of no cases where they would differ. Perhaps you could provide an example of whereNumber
andparseInt
differ in conversion of BigInts to numbers to enlighten me. Thank you very much.– Jack GCommented Feb 15, 2020 at 19:44 -
@JackGiffin You are totally right in this case of
BigInts
and what I need to show is thatparseInt
andNumber
have different behaviors and you can see the example in the link above. Commented Feb 15, 2020 at 20:15 -
2@I_Al-thamary: best practice is to use radix while using
parseInt
Commented Jan 7, 2022 at 13:30
Avoiding Caveats
I know the scope of the original question is knowing you already have a "safe integer", but I wanted to give scope to others that land here how they should try to handle it.
Number.isSafeInteger
One would think you could utilize Number.isSafeInteger
, but something trivial like the following snippet will show that utilizing the function on a BigInt
will always be false
even if the value is within the minimum and maximum bounds of a Number
.
console.log(Number.isSafeInteger(BigInt(1)))
// Returns false
An Implementation using Results
This utilizes the TS-Results library to return a success or error response, rather than doing something like throwing.
If you do not want to use the Results library, you could instead return the value and throw otherwise, or handle it however you see appropriate.
import { Err, Ok, Result } from 'ts-results'
export function bigIntToNumber(value: bigint): Result<number, Error> {
if (validInterger(value)) {
return Ok(Number(value))
}
return Err(new Error(`Value: "${value}" is out of bounds to be a Number`))
}
function validInteger(value: bigint): boolean {
return value <= Number.MAX_SAFE_INTEGER && value >= Number.MIN_SAFE_INTEGER
}
An Aside on Data Types and Data Ranges
Something interesting to note is that a JS number go up to 9,007,199,254,740,991
(the Number.MAX_SAFE_INTEGER
) while your classic 4-byte integer would only be 2,147,483,647
, thus a JS Number can hold more, but not as much as an 8-byte integer which goes up to
9,223,372,036,854,775,807
.
As noted in comments there can be numbers past Number.MAX_SAFE_INTEGER
up to Number.MAX_VALUE
that are still technically valid JS Numbers.
You can read more here:
-
Your last paragraph, as currently phrased, is incorrect. For example,
10_000_000_000_000_000_000
is totally a valid JS number. I know what you mean (2**53 - 1
is between2**31 - 1
and2**63 - 1
, sure!), but that's not what that paragraph is currently saying. Another way of putting it:Number.MAX_SAFE_INTEGER
!=Number.MAX_VALUE
. You're talking about the former, but JS numbers "go up to" (or "can hold" up to) the latter.– jmrkCommented Nov 10, 2023 at 14:17
Edit: see the discussion in the comments below as to why this answer is not correct. I am leaving the answer up regardless for disambiguation.
You should use either of the static methods:
BigInt.asIntN()
- Clamps a BigInt value to a signed integer value, and returns that value.
BigInt.asUintN()
- Clamps a BigInt value to an unsigned integer value, and returns that value.
as documented here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#static_methods
-
8@zr0gravity7 @naveen, I had the chance to test this and these methods do not return numbers, but BigInt values instead. Their names are misleading, as the
N
suggestsNumber
, when in fact they still return BigInt values. Try runningtypeof BigInt.asIntN(64, 1n)
to see that it reportsbigint
. So this answer actually does not answer the question. Commented Jan 7, 2022 at 14:57 -
1True that. A confusing name. Was reading the documentation. <3 Commented Jan 7, 2022 at 15:42
-
6The explanation of the name is that "intN" is the generalization of "int32", "int64", "int555" and so on; or put differently: "intN" is short for "N-bit integer". The value of this N is the first parameter to the function. An alternative spec could have provided
BigInt.asInt64(x)
andBigInt.asInt32(x)
, but for maximum flexibility the decision was made to have a singleBigInt.asIntN(N, x)
instead.– jmrkCommented Jan 12, 2022 at 11:35 -
4
as(Ui|I)ntN
does not do what you claim nor does this answer OP's question. These functions take a BigInt and return a BigInt modulo 2^N.– Chris_FCommented Aug 3, 2022 at 7:32