JavaScript の数値型が確実に扱える整数値の範囲は -9007199254740991 〜 9007199254740991
確実に使用できる整数値の範囲は最小値 Number.MIN_SAFE_INTEGER から最大値 Number.MAX_SAFE_INTEGER の間となる。それを超える値は処理系による。
const biggestInt = Number.MAX_SAFE_INTEGER // (253 - 1) => 9007199254740991
const smallestInt = Number.MIN_SAFE_INTEGER // -(253 - 1) => -9007199254740991JSON にシリアライズされたデータを解析する場合、整数値がこの範囲を超えていると、 JSON パーサーがこの値を Number 型に変換したときに信頼できない値になります。
可能な回避策として、代わりに String を使用してください。
大きい数値は BigInt 型を用いて表すことができます。
json-bigint ライブラリを使うと Number 型の範囲外の値をパースできる
JSON.parse/stringify with bigints support. Based on Douglas Crockford JSON.js package and bignumber.js library.
サンプルコード
今回の検証環境: macOS Catalina + Node.js v14.15.1 + json-bigint 1.0.0
$ node --version
v14.15.1
読み込む JSON ファイル (data.json)。
Number.MIN_SAFE_INTEGER (-9007199254740991) と Number.MAX_SAFE_INTEGER (9007199254740991) を超える値を記述している。
{
"under3": -99999999999999999,
"under2": -9999999999999999,
"under1": -9007199254740992,
"min": -9007199254740991,
"max": 9007199254740991,
"over1": 9007199254740992,
"over2": 9999999999999999,
"over3": 99999999999999999
}
標準ライブラリの JSON を使用した場合
ソースコード (json-parse.js)。
console.log(`整数の最小値: ${Number.MIN_SAFE_INTEGER}`);
console.log(`整数の最大値: ${Number.MAX_SAFE_INTEGER}`);
const fs = require('fs');
const data = JSON.parse(fs.readFileSync('data.json'));
console.log('under3:' + data.under3);
console.log('under2:' + data.under2);
console.log('under1:' + data.under1);
console.log('min: ' + data.min);
console.log('max: ' + data.max);
console.log('over1: ' + data.over1);
console.log('over2: ' + data.over2);
console.log('over3: ' + data.over3);
実行結果。
under1 と over1 は確実に使用できる値の範囲外ではあるが正確な値が出力された。
under3, under2, over2, over3 は不正確な値になってしまった。
$ node json-parse.js
整数の最小値: -9007199254740991
整数の最大値: 9007199254740991
under3:-100000000000000000
under2:-10000000000000000
under1:-9007199254740992
min: -9007199254740991
max: 9007199254740991
over1: 9007199254740992
over2: 10000000000000000
over3: 100000000000000000
json-bigint を使用した場合
ソースコード (json-bigint.js)。
console.log(`整数の最小値: ${Number.MIN_SAFE_INTEGER}`);
console.log(`整数の最大値: ${Number.MAX_SAFE_INTEGER}`);
const fs = require('fs');
const JSONbig = require('json-bigint');
const data = JSONbig.parse(fs.readFileSync('data.json'));
console.log('under3:' + data.under3);
console.log('under2:' + data.under2);
console.log('under1:' + data.under1);
console.log('min: ' + data.min);
console.log('max: ' + data.max);
console.log('over1: ' + data.over1);
console.log('over2: ' + data.over2);
console.log('over3: ' + data.over3);
実行結果。
確実に使用できる値の範囲外でも正確な値が出力されている。
$ node json-bigint.js
整数の最小値: -9007199254740991
整数の最大値: 9007199254740991
under3:-99999999999999999
under2:-9999999999999999
under1:-9007199254740992
min: -9007199254740991
max: 9007199254740991
over1: 9007199254740992
over2: 9999999999999999
over3: 99999999999999999