BigInt と Number を安全に混ぜて使うためのユーティリティライブラリ(高機能版)
目的
JavaScript では
10n + 5 // ❌ TypeError: Cannot mix BigInt and other types
JavaScriptのように、BigInt と Number を直接混ぜて計算できません。
このユーティリティは:
- 型を自動でそろえる
- 精度が失われる可能性を検出・警告
- 戻り型(BigInt or Number)を選べる
- ログ出力やフォールバック設定も可能
という「安全で柔軟な変換&演算レイヤー」を提供します。
コード全体
// bigint-utils.js
const BigNumUtils = (() => {
// ====== 設定 ======
const DEFAULT_OPTIONS = {
prefer: "bigint", // 戻り型の優先: "bigint" | "number" | "auto"
log: false, // 自動ログ出力するか
fallback: "error", // 精度喪失時の動作: "error" | "warn" | "truncate"
};
const MAX_SAFE = BigInt(Number.MAX_SAFE_INTEGER);
const MIN_SAFE = BigInt(Number.MIN_SAFE_INTEGER);
// ====== 内部関数 ======
function logIfNeeded(opts, msg, level = "info") {
if (!opts.log) return;
const tag = level === "warn" ? "⚠️" : "ℹ️";
console.log(`${tag} [BigNumUtils] ${msg}`);
}
function isSafeBigInt(bi) {
return bi <= MAX_SAFE && bi >= MIN_SAFE;
}
function toBigIntSafe(value, opts = DEFAULT_OPTIONS) {
if (typeof value === "bigint") return value;
if (typeof value === "number") {
if (!Number.isFinite(value)) throw new TypeError("Infinity や NaN は変換できません");
if (!Number.isInteger(value)) throw new RangeError("小数は BigInt に変換できません");
return BigInt(value);
}
throw new TypeError(`BigInt に変換できない型: ${typeof value}`);
}
function toNumberSafe(value, opts = DEFAULT_OPTIONS) {
if (typeof value === "number") return value;
if (typeof value === "bigint") {
if (!isSafeBigInt(value)) {
const msg = `Number の安全範囲 (${Number.MIN_SAFE_INTEGER}〜${Number.MAX_SAFE_INTEGER}) を超えています`;
if (opts.fallback === "error") throw new RangeError(msg);
if (opts.fallback === "warn") logIfNeeded(opts, msg, "warn");
}
return Number(value);
}
throw new TypeError(`Number に変換できない型: ${typeof value}`);
}
function unify(a, b, opts = DEFAULT_OPTIONS) {
const prefer = opts.prefer;
if (typeof a === typeof b) return [a, b];
// どちらか bigint どちらか number の場合
if (prefer === "bigint") {
return [toBigIntSafe(a, opts), toBigIntSafe(b, opts)];
} else if (prefer === "number") {
return [toNumberSafe(a, opts), toNumberSafe(b, opts)];
} else {
// auto: 安全なら number に、危険なら bigint に寄せる
if (typeof a === "bigint" && !isSafeBigInt(a)) return [a, toBigIntSafe(b)];
if (typeof b === "bigint" && !isSafeBigInt(b)) return [toBigIntSafe(a), b];
return [toNumberSafe(a), toNumberSafe(b)];
}
}
// ====== 公開API ======
return {
config(customOpts = {}) {
return { ...DEFAULT_OPTIONS, ...customOpts };
},
add(a, b, opts = DEFAULT_OPTIONS) {
const [x, y] = unify(a, b, opts);
const result = x + y;
logIfNeeded(opts, `add(${a}, ${b}) = ${result}`);
return result;
},
sub(a, b, opts = DEFAULT_OPTIONS) {
const [x, y] = unify(a, b, opts);
const result = x - y;
logIfNeeded(opts, `sub(${a}, ${b}) = ${result}`);
return result;
},
mul(a, b, opts = DEFAULT_OPTIONS) {
const [x, y] = unify(a, b, opts);
const result = x * y;
logIfNeeded(opts, `mul(${a}, ${b}) = ${result}`);
return result;
},
div(a, b, opts = DEFAULT_OPTIONS) {
const [x, y] = unify(a, b, opts);
if (y === 0n || y === 0) throw new RangeError("0 で割り算できません");
const result = x / y;
logIfNeeded(opts, `div(${a}, ${b}) = ${result}`);
return result;
},
toBigIntSafe,
toNumberSafe,
unify,
};
})();
JavaScript使い方例
例1:BigInt を優先して混合計算
const opts = BigNumUtils.config({ prefer: "bigint", log: true });
console.log(BigNumUtils.add(10n, 5, opts)); // → 15n(BigInt)
console.log(BigNumUtils.mul(9, 4n, opts)); // → 36n(BigInt)
JavaScriptログ出力例:
ℹ️ [BigNumUtils] add(10n, 5) = 15n
ℹ️ [BigNumUtils] mul(9, 4n) = 36n
JavaScript例2:Number 優先で統一
const opts = BigNumUtils.config({ prefer: "number" });
console.log(BigNumUtils.add(10n, 5, opts)); // → 15
JavaScript例3:auto(安全なら Number、危険なら BigInt)
const opts = BigNumUtils.config({ prefer: "auto", log: true });
const big = 9999999999999999999999999n;
console.log(BigNumUtils.add(big, 1, opts)); // → BigInt に統一(安全範囲超え)
JavaScript例4:フォールバック戦略
const opts = BigNumUtils.config({
prefer: "number",
fallback: "warn",
log: true
});
const big = 99999999999999999999n;
console.log(BigNumUtils.toNumberSafe(big, opts));
// ⚠️ 警告を出しつつ変換(精度が失われる可能性あり)
JavaScript機能まとめ
| 機能 | 説明 |
|---|---|
prefer | bigint / number / auto のどれを優先するか |
fallback | 精度超過時にどうするか:error(例外) / warn(警告出力) / truncate(そのまま切り捨て) |
log | true にすると内部処理ログを出力 |
toBigIntSafe() / toNumberSafe() | 個別変換関数(安全チェック付き) |
unify() | 混在した型を統一して返す内部関数 |
add() / sub() / mul() / div() | 自動変換付き算術演算 |
発展アイデア
もし次のステップに進めたいなら:
- 小数を自動的に切り捨て/四捨五入 して BigInt に変換できるモード
- BigDecimal(任意精度小数)風の実装 に拡張
- TypeScript 型定義 (
.d.ts) 付きバージョン - ブラウザ+Node.js 両対応のミニライブラリとして公開(npm対応)

