こんにちは!フロントエンド・アーキテクチャの世界へようこそ。
日々、JavaScriptと格闘していると、なんだか不思議なバグに遭遇して「うわっ、なんだこれ……」と頭を抱えたくなる瞬間がありますよね。大丈夫です、それ、みんな通る道ですから安心してください。
今日は、JavaScriptのデータ型の中でも、ちょっと頑固で、でもなくてはならない存在である「BigInt(ビッグイント)」についてお話しします。
「数字なんだから、一緒に計算させてよ!」と思わず愚痴りたくなるような、BigIntと他の型(特に通常のNumber)の切ない関係と、それを華麗に乗りこなすための知恵を、お買い物の例え話を交えながら優しく紐解いていきましょう。
—
1. そもそも「BigInt」ってどんなやつ?
JavaScriptの世界では、普段私たちが使う数字(整数も小数も)はすべて「Number型」という一つの箱に入れられています。このNumber型、普段のプログラミングなら全く問題ないのですが、実は一つだけ大きな弱点があります。
それは、「あまりにも大きすぎる数字を正確に覚えられない」ということ。
どれくらい大きいかと言うと、安全に扱える限界(`Number.MAX_SAFE_INTEGER`)を超えると、数字の末尾が勝手に丸められてしまい、計算が狂い始めます。宇宙の星の数や、超巨大なデータベースのID、あるいは最新の金融システムを扱うとき、これは大問題です。
そこで登場したのが、どんなに桁数が多くても正確に数字を扱えるスーパーマン、「BigInt(大きな整数)」です。数字の最後に「`n`」をポツンとつけるだけで、JavaScriptくんに「これは特別な大男なんだぜ」と教えてあげられます。
// 普通の数字(Number型)の限界を超える巨大な数
const hugeNumber = 9007199254740991n; // 末尾の ‘n’ が BigInt の証拠!
—
2. なぜ、BigIntは普通のNumberと混ぜて使えないのか?
さて、ここからが本題であり、多くの開発者が最初に躓く「壁」です。
JavaScriptさんは、気まぐれに勝手な型変換(暗黙の型変換)をしてくれることで有名ですよね。「`”5″ + 3`」と書けば、気を利かせて文字列の`”53″`にしてくれたりします。
じゃあ、「BigIntの巨大な数字」と「普通のNumberの数字」を足し算したらどうなると思います?
const moneyBigInt = 100n;
const taxNumber = 10;
// さあ、計算してみよう!
console.log(moneyBigInt + taxNumber); // 💥 エラーが起きます!
// TypeError: Cannot mix BigInt and other types (use explicit conversion)
「おいおい、どっちも数字なんだから、よしなに計算してよ!」と思いますよね。でも、JavaScriptはここでわざわざエラーを投げて止まります。 なぜでしょうか?
お買い物で例えてみましょう
ここに、「地球に数個しかない、超精密なオーダーメイドのダイヤモンド(BigInt)」と、「スーパーのレジ袋に入った普通の硬貨(Number)」があるとします。
この2つを「どっちも『価値のあるもの』だから一緒のポケットにジャラジャラ混ぜていいよね!」とやったらどうなるでしょう? 硬貨の重みでダイヤモンドの繊細なカットが傷つくかもしれないし、逆にダイヤモンドの価値に目が眩んで硬貨の正確な枚数がわからなくなるかもしれません。
JavaScriptの生みの親や仕様を決めた偉い人たちは、「違うスケールの数字を勝手に混ぜて計算させると、思わぬ精度落ちやバグの温床になる!」と考えました。そのため、「混ぜるなら、ちゃんとルールに従って、お互いの形を揃えてからにしなさい!」と、あえて厳しくエラーを出す仕様にしたのです。これがBigIntの厳格な制約の理由です。
—
3. 解決策:明示的に型を揃えてあげよう
じゃあ、実務でBigIntとNumberを一緒に使いたいときはどうすればいいのでしょうか?
答えはシンプルです。「お互いの姿かたちを、どちらかに合わせてあげる(明示的な変換)」のです。
現場でよく使われる2つのアプローチを見てみましょう。
パターンA:Numberを BigInt に合わせる
もし計算する数字が「そんなにバカデカくない(Numberの安全な範囲内)」とわかっているなら、普通の数字をBigIntに変換して合流させます。
const userBalance = 5000n; // 所持金(BigInt)
const bonusRate = 2; // ボーナス倍率(普通のNumber)
// bonusRate を BigInt(2n) に変換してから計算する!
const totalMoney = userBalance BigInt(bonusRate);
console.log(totalMoney); // 10000n (無事に計算できました!)
パターンB:BigIntを Number に合わせる
「BigIntの巨大な正確さはもう用済みで、画面表示のために普通の数字として扱いたい」という場合は、Number型に落とし込みます。
※ただし、数字が大きすぎると精度が落ちる(丸められる)リスクがあるので、そこだけは注意が必要です!
const hugeId = 123456789012345678n; // 巨大なID
// Number() で囲って、普通の数字に変換!
const normalIdNumber = Number(hugeId);
console.log(normalIdNumber); // 123456789012345680000…みたいな感じ(※大きな数字は精度に注意!)
console.log(typeof normalIdNumber); // “number”
—
4. 実務で役立つ!ちょっとした注意点とテクニック
最後に、現場でBigIntを扱うときに知っておくと救われる小ネタをいくつか。
1. 比較演算子(`>` や `<`)は、実は混ぜても動く
足し算や引き算(算術演算)は厳しくエラーになりますが、大小の比較(例: `100n > 5`)は、JavaScriptが気を利かせて正しく判定してくれます。とはいえ、コードの読みやすさや予期せぬバグを防ぐためにも、型はなるべく揃えるのがプロの作法です。
2. JSON.stringify でそのままシリアライズできない
API通信などでよく使う `JSON.stringify()` ですが、オブジェクトの中に BigInt が混ざっていると「`TypeError: Do not know how to serialize a BigInt`」と怒られてフリーズします。BigIntをJSONにする時は、あらかじめ `.toString()` などで文字列に変換してあげる必要があります。
const data = { id: 9007199254740991n };
// JSONにする前に文字列にしておく
const safeData = { id: data.id.toString() };
console.log(JSON.stringify(safeData)); // ‘{“id”:”9007199254740991″}’
—
まとめ
いかがでしたでしょうか? BigIntと他の型が混ざれないのは、JavaScriptの意地悪ではなく、私たちの手元の大切なデータを予期せぬ精度のバグから守るための優しさなんです。
もし今後、開発中に `TypeError: Cannot mix BigInt and other types` というエラーに遭遇したら、「あ、今ダイヤモンドと硬貨を同じポケットに入れようとしちゃったな」と思い出してください。そして、`BigInt()` や `Number()` でそっと形を揃えてあげれば、エラーはすんなり消えてくれますよ。
日々のコーディングが、少しでも楽しく、スムーズになりますように。
それでは、また次の現場でお会いしましょう!

コメント