最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to make JSON.parse() to treat all the Numbers as BigInt? - Stack Overflow

programmeradmin6浏览0评论

I have some numbers in json which overflow the Number type, so I want it to be bigint, but how?

{"foo":[[0],[64],[89],[97]],"bar":[[2323866757078990912,144636906343245838,441695983932742154,163402272522524744],[2477006750808014916,78818525534420994],[18577623609266200],[9008333127155712]]}

I have some numbers in json which overflow the Number type, so I want it to be bigint, but how?

{"foo":[[0],[64],[89],[97]],"bar":[[2323866757078990912,144636906343245838,441695983932742154,163402272522524744],[2477006750808014916,78818525534420994],[18577623609266200],[9008333127155712]]}
Share Improve this question edited Oct 21, 2021 at 9:13 Yevhen Horbunkov 15.5k3 gold badges26 silver badges45 bronze badges asked Oct 20, 2021 at 10:27 mihebomihebo 1151 gold badge1 silver badge5 bronze badges 3
  • 1 Probably there's answer available here: node.js - Is there any proper way to parse JSON with large numbers? (long, bigint, int64) – koloml Commented Oct 20, 2021 at 10:34
  • SAD. I'd like to get some build-in solution... – mihebo Commented Oct 20, 2021 at 10:37
  • I suggest to use strings and then convert them into BigInt numbers. Like some REST APIs doing (like Discord API with BigInt IDs). It's much easier and you event can convert such variables to BigInt using built-in converter. – koloml Commented Oct 20, 2021 at 10:39
Add a comment  | 

2 Answers 2

Reset to default 17

TLDR;

You may employ JSON.parse() reviver parameter

Detailed Solution

To control JSON.parse() behavior that way, you can make use of the second parameter of JSON.parse (reviver) - the function that pre-processes key-value pairs (and may potentially pass desired values to BigInt()).

Yet, the values recognized as numbers will still be coerced (the credit for pinpointing this issue goes to @YohanesGultom).

To get around this, you may enquote your big numbers (to turn them into strings) in your source JSON string, so that their values are preserved upon converting to bigint.

As long as you wish to convert to bigint only certain numbers, you would need to pick up appropriate criteria (e.g. to check whether the value exceeds Number.MAX_SAFE_INTEGER with Number.isSafeInteger(), as @PeterSeliger has suggested).

Thus, your problem may be solved with something, like this:

// source JSON string

const input = `{"foo":[[0],[64],[89],[97]],"bar":[[2323866757078990912,144636906343245838,441695983932742154,163402272522524744],[2477006750808014916,78818525534420994],[18577623609266200],[9008333127155712]]}`


// function that implements desired criteria
// to separate *big numbers* from *small* ones
//
// (works for input parameter num of type number/string)

const isBigNumber = num => !Number.isSafeInteger(+num)


// function that enquotes *big numbers* matching
// desired criteria into double quotes inside
// JSON string
//
// (function checking for *big numbers* may be
// passed as a second parameter for flexibility)

const enquoteBigNumber = (jsonString, bigNumChecker) =>
    jsonString
        .replaceAll(
            /([:\s\[,]*)(\d+)([\s,\]]*)/g,
            (matchingSubstr, prefix, bigNum, suffix) =>
                bigNumChecker(bigNum)
                    ? `${prefix}"${bigNum}"${suffix}`
                    : matchingSubstr
        )


// parser that turns matching *big numbers* in
// source JSON string to bigint

const parseWithBigInt = (jsonString, bigNumChecker) =>
    JSON.parse(
        enquoteBigNumber(jsonString, bigNumChecker),
        (key, value) =>
            !isNaN(value) && bigNumChecker(value)
                ? BigInt(value)
                : value
    )

// resulting output

const output = parseWithBigInt(input, isBigNumber)


console.log("output.foo[1][0]: \n", output.foo[1][0], `(type: ${typeof output.foo[1][0]})`)
console.log("output.bar[0][0]: \n", output.bar[0][0].toString(), `(type: ${typeof output.bar[0][0]})`)
.as-console-wrapper{min-height: 100% !important;}

Note: you may find RegExp pattern to match strings of digits among JSON values not quite robust, so feel free to come up with yours (as mine was the quickest I managed to pick off the top of my head for demo purposes)

Note: you may still opt in for some library, as it was suggested by @YohanesGultom, yet adding 10k to your client bundle or 37k to your server-side dependencies (possibly, to docker image size) for that sole purpose may not be quite reasonable.

You can try my library that solves this problem: https://www.npmjs.com/package/json-with-bigint

Example:

import { JSONParse } from 'json-with-bigint';
    
const yourJSON = `{"someValue":42,"someBigValue":10000000000000000365}`;

JSONParse(yourJSON); // { someValue: 42, someBigValue: 10000000000000000365n }

Library will automatically figure out what values are BigInt, so no need to pass a list of specific keys with BigInt values.

It also supports consistent round-trip operations (parse - stringify - parse). Deserialized values will be the same as the ones you serialized initially and vice versa.

import { JSONParse, JSONStringify } from 'json-with-bigint';
    
const yourJSON = `{"someValue":42,"someBigValue":10000000000000000365}`;

JSONParse(yourJSON); // { someValue: 42, someBigValue: 10000000000000000365n }
JSONStringify(data); // '{"someValue":42,"someBigValue":10000000000000000365}'
JSONParse(JSONStringify(data)); // { someValue: 42, someBigValue: 10000000000000000365n }
发布评论

评论列表(0)

  1. 暂无评论