JSON に記述された数値型の範囲外の整数値を JavaScript でパースする

## JavaScript の数値型が確実に扱える整数値の範囲は -9007199254740991 〜 9007199254740991

確実に使用できる整数値の範囲は最小値 Number.MIN_SAFE_INTEGER から最大値 Number.MAX_SAFE_INTEGER の間となる。それを超える値は処理系による。

[Number \- JavaScript \| MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Number)

> const biggestInt  = Number.MAX_SAFE_INTEGER  //  (253 - 1) =>  9007199254740991
> const smallestInt = Number.MIN_SAFE_INTEGER  // -(253 - 1) => -9007199254740991
> 
> JSON にシリアライズされたデータを解析する場合、整数値がこの範囲を超えていると、 JSON パーサーがこの値を Number 型に変換したときに信頼できない値になります。
> 可能な回避策として、代わりに String を使用してください。
> 大きい数値は BigInt 型を用いて表すことができます。

## json-bigint ライブラリを使うと Number 型の範囲外の値をパースできる

[json\-bigint \- npm](https://www.npmjs.com/package/json-bigint)

> 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) を超える値を記述している。

```json
{
  "under3": -99999999999999999,
  "under2": -9999999999999999,
  "under1": -9007199254740992,
  "min":    -9007199254740991,
  "max":     9007199254740991,
  "over1":   9007199254740992,
  "over2":   9999999999999999,
  "over3":   99999999999999999
}
```

### 標準ライブラリの JSON を使用した場合

ソースコード (json-parse.js)。

```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)。

```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
```

## 参考資料

- [JSON \- JavaScript \| MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/JSON)
- [Number \- JavaScript \| MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Number)
- [BigInt \- JavaScript \| MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/BigInt)
- [json\-bigint \- npm](https://www.npmjs.com/package/json-bigint)