Not with built-in JSON.parse. You'll need to parse it manually and treat values as string (if you want to do arithmetics with them there is bignumber.js) You can use Douglas Crockford JSON.js library as a base for your parser.
EDIT2 ( 7 years after original answer ) - it might soon be possible to solve this using standard JSON api. Have a look at this TC39 proposal to add access to source string to a reviver function - https://github.com/tc39/proposal-json-parse-with-source
EDIT1: I created a package for you :)
var JSONbig = require('json-bigint');
var json = '{ "value" : 9223372036854775807, "v2": 123 }';
console.log('Input:', json);
console.log('');
console.log('node.js bult-in JSON:')
var r = JSON.parse(json);
console.log('JSON.parse(input).value : ', r.value.toString());
console.log('JSON.stringify(JSON.parse(input)):', JSON.stringify(r));
console.log('\n\nbig number JSON:');
var r1 = JSONbig.parse(json);
console.log('JSON.parse(input).value : ', r1.value.toString());
console.log('JSON.stringify(JSON.parse(input)):', JSONbig.stringify(r1));
Output:
Input: { "value" : 9223372036854775807, "v2": 123 }
node.js bult-in JSON:
JSON.parse(input).value : 9223372036854776000
JSON.stringify(JSON.parse(input)): {"value":9223372036854776000,"v2":123}
big number JSON:
JSON.parse(input).value : 9223372036854775807
JSON.stringify(JSON.parse(input)): {"value":9223372036854775807,"v2":123}
Answer from Andrey Sidorov on Stack Overflow
» npm install json-bigint
TypeError: Do not know how to serialize a BigInt at JSON.stringify (<anonymous>)
node.js - Is there any proper way to parse JSON with large numbers? (long, bigint, int64)
How to make JSON.parse() to treat all the Numbers as BigInt?
typescript - Serialize BigInt in JSON - Stack Overflow
Not with built-in JSON.parse. You'll need to parse it manually and treat values as string (if you want to do arithmetics with them there is bignumber.js) You can use Douglas Crockford JSON.js library as a base for your parser.
EDIT2 ( 7 years after original answer ) - it might soon be possible to solve this using standard JSON api. Have a look at this TC39 proposal to add access to source string to a reviver function - https://github.com/tc39/proposal-json-parse-with-source
EDIT1: I created a package for you :)
var JSONbig = require('json-bigint');
var json = '{ "value" : 9223372036854775807, "v2": 123 }';
console.log('Input:', json);
console.log('');
console.log('node.js bult-in JSON:')
var r = JSON.parse(json);
console.log('JSON.parse(input).value : ', r.value.toString());
console.log('JSON.stringify(JSON.parse(input)):', JSON.stringify(r));
console.log('\n\nbig number JSON:');
var r1 = JSONbig.parse(json);
console.log('JSON.parse(input).value : ', r1.value.toString());
console.log('JSON.stringify(JSON.parse(input)):', JSONbig.stringify(r1));
Output:
Input: { "value" : 9223372036854775807, "v2": 123 }
node.js bult-in JSON:
JSON.parse(input).value : 9223372036854776000
JSON.stringify(JSON.parse(input)): {"value":9223372036854776000,"v2":123}
big number JSON:
JSON.parse(input).value : 9223372036854775807
JSON.stringify(JSON.parse(input)): {"value":9223372036854775807,"v2":123}
After searching something more clean - and finding only libs like jsonbigint, I just wrote my own solution. Is not the best, but it solves my problem. For those that are using Axios you can use it on transformResponse callback (this was my original problem - Axios parses the JSON and all bigInts cames wrong),
const jsonStr = `{"myBigInt":6028792033986383748, "someStr":"hello guys", "someNumber":123}`
const result = JSON.parse(jsonStr, (key, value) => {
if (typeof value === 'number' && !Number.isSafeInteger(value)) {
let strBig = jsonStr.match(new RegExp(`(?:"${key}":)(.*?)(?:,)`))[1] // get the original value using regex expression
return strBig //should be BigInt(strBig) - BigInt function is not working in this snippet
}
return value
})
console.log({
"original": JSON.parse(jsonStr),
"handled": result
})
» npm install json-with-bigint
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:
Copy// 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]})`)
Copy.as-console-wrapper{min-height: 100% !important;}
Run code snippetEdit code snippet Hide Results Copy to answer Expand
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:
Copyimport { 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.
Copyimport { 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 }
You could use the replacer argument for JSON.stringify like this:
const obj = {
foo: 'abc',
bar: 781,
qux: 9n
}
JSON.stringify(obj, (_, v) => typeof v === 'bigint' ? v.toString() : v)
BigInt to JSON in 2024
There is no single correct method to use in every case. As explained by Jakob Kummerow in a discussion in a Google Chrome Labs GitHub repository:
Working as intended/spec'ed: https://tc39.es/proposal-bigint/#sec-serializejsonproperty (step 10).
In short, the background is that JSON is so commonly used among all sorts of different systems and programming languages that it is effectively impossible to add anything to the format without breaking compatibility in some crucial case.
You can define your own .toJSON() function, and pass a corresponding "reviver" function as an argument to JSON.parse(). That way, at least you have control over any (backwards) compatibility issues.
Typescript (and Javascript), by default, will not create a BigInt value when parsing JSON no matter how large the number is. It will parse it as the nearest number, silently ignoring errors with precision.
There are a few ways to work around this, but they depend on you having control over both stringfying and parsing the JSON. Otherwise, the JSON you produce may not parse correctly because it violates standards.
Here are a few methods:
Use a structured string as a go-between
What I propose is to stringify BigInt as a quoted string ending in n, which is very similar to the standard way of specifying BigInt numbers, making them human-readable and easy to convert automatically. To accomplish this, you need to define a replacer and reviver function:
function bigIntReplacer(key: string, value: any): any {
if (typeof value === "bigint") {
return value.toString() + 'n';
}
return value;
}
function bigIntReviver(key: string, value: any): any {
if (typeof value === 'string' && /^\d+n$/.test(value)) {
return BigInt(value.slice(0, -1));
}
return value;
}
Now you can use these when calling JSON.stringify and JSON.parse like this:
const bigInteger = BigInt(Number.MAX_SAFE_INTEGER) * BigInt(8);
// Stringify using the replacer
const jsonBigInteger = JSON.stringify(bigInteger, bigIntReplacer);
// Print JSON to show it is a string
console.log(`As JSON, it is a ${typeof jsonBigInteger} containing: ${jsonBigInteger}`);
// Parse it from JSON
const fromJsonBigInteger = JSON.parse(jsonBigInteger, bigIntReviver);
// Print that number to show it is a bigint
console.log(`After passing through JSON, it is a ${typeof fromJsonBigInteger} containing ${fromJsonBigInteger.toString()}`);
Use an object as a go-between
Another method, although more verbose, is to use an object as a go-between. You can serialize your BigInt as an object that contains a field indicating that the object is a BigInt and another field holding the value. There is a bignumberify library that uses this method. It relies on the fact that JSON.stringify accepts a replacer function, and JSON.parse accepts a reviver function, both as an optional second parameter.
The author of that library gives an example of what a BigInt holding 125000n would serialize as:
{
"type": "BigInt",
"hex": "0x01e848"
}
Their library relies on a function that must be passed to the JSON.stringify:
const jsonStr = JSON.stringify(obj, bigNumberify.stringify);
This is great because it avoids potential conflicts with other libraries and future modifications to the standards that are caused by modifying BigInt's prototype.
However, I think an object like that adds bloat while preventing the value from being human-readable (unless you consider hexadecimal to be human-readable). It also eliminates a major benefit of JSON, which is the direct correlation between the structure in JSON and the structure when parsed. A compatible parser will produce a different tree than standard ones would. I prefer a method that maintains the precision of the string method with the convenience of the number method and without the bloat of the object method.
Use strings as a go-between
WARNING: Modifying the prototype of standard Javascript objects is discouraged for very good reasons. If you are publishing a library, PLEASE DO NOT DO IT!
If you convert your BigInt into a string, it will be parsed as one. However, this may be acceptable when you know which field will be a string. You can just convert it explicitly when you encounter it. To do this, you can modify the prototype of BigInt as described by Holger Jeromin.
// eslint-disable-next-line @typescript-eslint/no-redeclare
interface BigInt {
/** Convert to BigInt to string form in JSON.stringify */
toJSON: () => string;
}
BigInt.prototype.toJSON = function () {
return this.toString();
};
Or, if you're not using strict Typescript:
BigInt.prototype["toJSON"] = function () {
return this.toString();
};
Someone with the paradoxical username noskill24 suggested a polyfill that ensures there is no existing .toJSON() before installing it:
// Polyfill: BigInt.prototype.toJSON
(function(global, undefined) {
if (global.BigInt.prototype.toJSON === undefined) {
global.Object.defineProperty(global.BigInt.prototype, "toJSON", {
value: function() { return this.toString(); },
configurable: true,
enumerable: false,
writable: true
});
}
})(window !== void 0 ? window : typeof global !== void 0 ? global : typeof self !== void 0 ? self : this);
Use numbers as a go-between
You could just convert to a Number and let that get serialized as JSON. This method looks exactly like the previous one, except you'll use Number(this) instead of this.toString().
WARNING: This method has a major flaw. It loses precision. This means the number you receive might be close to the number you sent, but not exactly the same.
--
No method is perfect, but I hope this has been a good summary of the available options.
» npm install json-bigint-patch
» npm install json-bigint-native