aboutsummaryrefslogtreecommitdiff

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.