BigInt and JSON.stringify/JSON.parse

Ben Lesh - Jan 4 '21 - - Dev Community

As of this writing, JavaScript's JSON.parse cannot serialize the new JavaScript type BigInt.

Imagine you have the following:

const data = {
  value1: BigInt('1231231231231231213'),
  deep: {
    // NOTE the "n" at the end -- also a BigInt!
    value2: 848484848484848484884n,
  }
}
Enter fullscreen mode Exit fullscreen mode

If you try to just JSON.stringify(data) you will get the error TypeError: Do not know how to serialize a BigInt.

Serialization and Deserialization

It should be noted that how you choose to serialize your BigInts affects how you deserialize your BigInts. Generally, I serialize them by doing appending the "n" suffix to the end, similar to how we can declare a BigInt inline. (BigInt(0) and 0n yield the same result).

Serialization

Here we use JSON.stringify's second argument (It's not always null!!! haha.) which is the replacer. The job of this function, if provided, is to determine how to serialize something based off of it's key and value. If the typeof the value is "bigint", we're going to convert it to a string, and tack an "n" to the end.

// Serialization
const json = JSON.stringify(data, (key, value) =>
  typeof value === "bigint" ? value.toString() + "n" : value
);
Enter fullscreen mode Exit fullscreen mode

The result: json is:

{
  "value1": "1231231231231231213n",
  "deep": {
    "value2": "848484848484848484884n",
  }
}
Enter fullscreen mode Exit fullscreen mode

Deserialization

In order to deserialize what we have above, we can use the second argument to JSON.parse(). (I bet most people didn't know it has a second argument) This is called the reviver, and it's job is to do basically the opposite of the replacer above.

Here we'll test for the type and shape of the value to see that it matches a bunch of numbers followed by an "n".

// Deserialize
const backAgain = JSON.parse(json, (key, value) => {
  if (typeof value === "string" && /^\d+n$/.test(value)) {
    return BigInt(value.substr(0, value.length - 1));
  }
  return value;
});
Enter fullscreen mode Exit fullscreen mode

Alternative serializations

This is all a little tricky, because you have to be sure that none of your other data is in a format where it's a bunch of numbers and an "n" at the end. If it is, you need to change your serialization strategy. For example, perhaps you serialize to BigInt::1231232123 and deserialize the same at the other side, such as the example below:

// Serialize
const json = JSON.stringify(data, (key, value) =>
  typeof value === "bigint" ? `BIGINT::${value}` : value
);

// Deserialize
const backAgain = JSON.parse(json, (key, value) => {
  if (typeof value === "string" && value.startsWith('BIGINT::')) {
    return BigInt(value.substr(8));
  }
  return value;
});
Enter fullscreen mode Exit fullscreen mode

The choice is really up to you, just as long as you have the tools to do it.

. . . .