title: Encoding and decoding JavaScript BigInt values with reviver
date: 2021-08-11
updated_at: 2021-08-13
layout: post
lang: en
ref: encoding-and-decoding-javascript-bigint-values-with-reviver
JSON.parse()
accepts a second parameter: a reviver()
function.
It is a function that can be used to transform the JSON
values as they're
being parsed.
As it turns out, when combined with JavaScript's [BigInt
] type, you can parse
and encode JavaScript BigInt
numbers via JSON:
const bigIntReviver = (_, value) =>
typeof value === "string" && value.match(/^-?[0-9]+n$/)
? BigInt(value.slice(0, value.length - 1))
: value;
I chose to interpret strings that contains only numbers and an ending n
suffix
as BigInt
values, similar to how JavaScript interprets 123
(a number)
differently from 123n
(a bigint
);
We do those checks before constructing the BigInt
to avoid throwing needless
exceptions and catching them on the parsing function, as this could easily
become a bottleneck when parsing large JSON values.
In order to do the full roundtrip, we now only need the toJSON()
counterpart:
BigInt.prototype.toJSON = function() {
return this.toString() + "n";
};
With both bigIntReviver
and toJSON
defined, we can now successfully parse
and encode JavaScript objects with BigInt
values transparently:
const s = `[
null,
true,
false,
-1,
3.14,
"a string",
{ "a-number": "-123" },
{ "a-bigint": "-123n" }
]`;
const parsed = JSON.parse(s, bigIntReviver);
const s2 = JSON.stringify(parsed);
console.log(parsed);
console.log(s2);
console.log(typeof parsed[6]["a-number"])
console.log(typeof parsed[7]["a-bigint"])
The output of the above is:
[
null,
true,
false,
-1,
3.14,
'a string',
{ 'a-number': '-123' },
{ 'a-bigint': -123n }
]
[null,true,false,-1,3.14,"a string",{"a-number":"-123"},{"a-bigint":"-123n"}]
string
bigint
If you're on a web browser, you can probably try copying and pasting the above code on the console right now, as is.
Even though [JSON
] doesn't include BigInt
number, encoding and decoding them
as strings is quite trivial on JavaScript.