-
Notifications
You must be signed in to change notification settings - Fork 67
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JSON.stringify() doesn't know how to serialize a BigInt #30
Comments
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 |
@jakobkummerow Ok, makes sense. For anyone else stumbling upon this, the verified TL;DR fix for the above problem is:
|
-changed var to let, as recommended by mozilla: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/Variables#the_difference_between_var_and_let -The duplicate detector had bugs that assumes two entries are different that should be the same, which is now fixed: --Whether or not if there is a tab after the size/ending_address --If there are a leading zero in the size/ending_address. --I also learn that you cannot use JSON.stringify() if the thing has a bigint data type in it (results in this: GoogleChromeLabs/jsbi#30 )
Wouldn't it be easier to just monkey patch (hijack) BigInt.prototype.toJSON = function() { return this.toString() } If you do it this way, you don't have to add an anonymous function into every call of |
@ADTC answer will only work with pure javascript. With typescript I get the error: |
@phoenixbeats01 you can do this if you are using typescript (BigInt.prototype as any).toJSON = function () {
return this.toString();
}; |
Or cleaner with the "I know what I do" feature: BigInt.prototype["toJSON"] = function () {
return this.toString();
}; Or better (for strict TS configs) with the TS declaration: // 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();
}; |
Element implicitly has an 'any' type because expression of type '"toJSON"' can't be used to index type 'BigInt'. |
Oh, I had |
If you're trying to use this with Typescript, I suggest you create a .ts or .js file with: // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore: Unreachable code error
BigInt.prototype.toJSON = function (): number {
return this.toString();
}; You can also return Number(this), but I suggest toString as it has no character limiter. However, it will depend on your context. After that, you must import or require this file in your main file (like index.ts/.js or main.ts, etc). If you are trying to run tests with Jest, you must add this file in the installation configuration. These settings can be created in package.json with "jest: { .... }" or in a file called jest.config.ts (create this in the root). Example: export default {
testTimeout: 30000,
moduleFileExtensions: ['js', 'json', 'ts'],
**setupFiles: ['./my_config_file'],**
testRegex: '.*\\.spec\\.ts$',
transform: {
'^.+\\.(t|j)s$': 'ts-jest',
},
collectCoverageFrom: ['**/*.(t|j)s'],
coverageDirectory: '../coverage',
testEnvironment: 'node',
} At this point you can create a test module, with many configs, and create an index file that imports all the configs, and just pass this index file in the setupFiles config from jest. |
The issue with serializing a BigInt as a string is that during the parsing you must know what any property is to know which ones should stay as strings and which ones should become big integers. It would be better to use an approach similar to how BigNumber instances are stringified like this {
"type": "BigNumber",
"hex": "0x01e848"
} I just added to bigNumberify support for BigInt values, so that the BigInt {
"type": "BigInt",
"hex": "0x01e848"
} and parsed back without ambiguities. Any feedback would be appreciated. |
I guess the process can be like this:
parse:
Hope this makes sense |
This is it! // Wrapper around JSON stringify/parse methods to support bigint serialization
function replacer(key, value) {
if (typeof value === "bigint") {
return {
__type: "bigint",
__value: value.toString(),
};
} else {
return value;
}
}
function reviver(key, value) {
if (value && value.__type == "bigint") {
return BigInt(value.__value);
}
return value;
}
export const json_stringify = (obj) => {
return JSON.stringify(obj, replacer);
};
export const json_parse = (s) => {
return JSON.parse(s, reviver);
}; |
I found this solution more elegant, works for typescript too:
Object.defineProperty(BigInt.prototype, "toJSON", {
get() {
"use strict";
return () => String(this);
}
}); As somebody of you have commented before, you can put this into a file and import it to have it into the global scope with |
worked for me elegant |
|
Modifying the global BigInt and involving Please don't modify the global so that the next developer has to spend time finding your elegant solution 🙏 function bigIntReplacer(_key: string, value: any): any {
return typeof value === 'bigint' ? value.toString() : value;
}
JSON.stringify({ "my_big_int": 1122n }, bigIntReplacer);
// '{"my_big_int":"1122"}' |
I am using strict typing, and the following setup works for me: // src/types/global.d.ts
interface BigInt {
toJSON: () => string;
} // src/main.ts
BigInt.prototype.toJSON = function () {
return this.toString();
}; |
The JSON specification allows arbitrarily large integers, and in some cases you might want to actually serialize bigints as syntactical JSON integers and not strings; e.g. when communicating with services that properly support parsing such integers. You can now do this using For example: function bigintReplacer(key, value) {
if (typeof value === "bigint") {
return JSON.rawJSON(value.toString());
} else {
return value;
}
}
// Returns '{"foo":119257819285912598125125}'
JSON.stringify({ foo: 119257819285912598125125n }, bigintReplacer) Note however that this only works for serialization and not for parsing. |
Not certain how to handle this situation:
The text was updated successfully, but these errors were encountered: