bigint json序列化会抛typeerror而非降级,因json标准不支持;可通过replacer函数或预处理统一转换为字符串,避免修改原型带来的风险。

BigInt 在 JSON 序列化时不会静默降级,而是直接抛出 TypeError: Do not know how serialize a BigInt —— 这就是最明确的崩溃信号。它出现在调用 JSON.stringify() 且数据中包含未处理的 123n 类型值的瞬间,常见于 Prisma、Drizzle 或数据库查询返回的 ID、计数、大金额字段。
为什么原生不支持?
JSON 标准(RFC 7159)只定义了六种基础类型,不包含任意精度整数。BigInt 是 JavaScript 后来引入的独立类型,语义和底层表示都与 Number 不同,引擎无法安全映射——强行转成数字会丢失精度(比如 9007199254740993n 转 Number 就变成 9007199254740992),所以设计上选择显式报错,而非隐式出错。
toJSON 方法的作用不是“修复”,而是“声明意图”
toJSON 是 JSON.stringify 内部约定的钩子函数:当遍历到某个对象属性时,如果该属性值有 toJSON 方法,就会优先调用它,并用其返回值参与序列化。对 BigInt 来说:
- 它本身没有
toJSON方法(标准未定义) - 你手动添加
BigInt.prototype.toJSON = function() { return this.toString(); },等于告诉JSON.stringify:“遇到任何 BigInt,别报错,请用它的字符串形式代替” - 这样就绕过了默认的“不认识就炸”逻辑,转为可控的转换
但要注意:toJSON 不是万能解法
这个方法看似简洁,实际有明显限制:
- TypeScript 编译会报错,因
BigInt类型定义中不含toJSON,需额外声明或禁用检查 - 修改内置原型存在全局风险,可能与其他库冲突(尤其在大型项目或微前端中)
- 它只影响
JSON.stringify,不影响反序列化;字符串回来后仍是字符串,不会自动变回BigInt
更推荐的识别与应对方式
与其依赖原型修改,不如在序列化入口统一拦截:
- 用
replacer函数判断typeof value === 'bigint',返回value.toString() - 在 API 响应前(如 Remix 的
json()、Nest 的res.json())做预处理 - 对关键字段命名加约定(如
userId_big),便于后续reviver精准还原











