TypeScript中BigNumber数组转普通数字遇报错的技术问询
Ethers.js中批量转换BigNumber数组的问题解决
问题场景
有一个包含BigNumber类型字段的对象arr,结构如下:
{ size: BigNumber { value: '2' }, pricePerDay: [ BigNumber { value: '103897429' }, BigNumber { value: '103827546' } ], unixDate: [ BigNumber { value: '1670268628' }, BigNumber { value: '1670268634' } ] }
单个BigNumber用toNumber()可以正常转换,但直接对数组调用toNumber()会报错;用map批量转换时,遇到超过JavaScript安全整数范围的值会触发溢出错误。
错误原因分析
- 数组调用toNumber报错:
pricePerDay和unixDate是数组,不是单个BigNumber实例,没有toNumber()方法,必须遍历数组逐个转换元素。 - 溢出错误:JavaScript的
Number类型最大安全整数是2^53 - 1(约9e15),当BigNumber的值超过这个范围时,toNumber()会丢失精度并抛出溢出错误。
解决方案
1. 修复数组转换的基本逻辑
先修正代码里的语法错误和逻辑错误:
- 函数定义缺少闭合括号
- 应用转换时
newArr未初始化,且unixDate错误传入了arr.pricePerDay
正确的数组转换函数:
function arrayBigNumberToNumber(arr: BigNumber[]): number[] { return arr.map(element => element.toNumber()); } // 应用转换(原对象只读,需创建新对象) const newObj = { size: arr.size.toNumber(), pricePerDay: arrayBigNumberToNumber(arr.pricePerDay), unixDate: arrayBigNumberToNumber(arr.unixDate) };
2. 处理溢出问题
如果BigNumber值可能超过JavaScript安全整数范围,推荐以下两种方式:
方式一:转换为字符串
如果不需要进行数值计算,直接用toString()转为字符串避免溢出:
function arrayBigNumberToString(arr: BigNumber[]): string[] { return arr.map(element => element.toString()); } const newObj = { size: arr.size.toString(), pricePerDay: arrayBigNumberToString(arr.pricePerDay), unixDate: arrayBigNumberToString(arr.unixDate) };
方式二:转换为BigInt(ES2020+支持)
如果需要进行大整数运算,用toBigInt()转为原生BigInt类型:
function arrayBigNumberToBigInt(arr: BigNumber[]): bigint[] { return arr.map(element => element.toBigInt()); } const newObj = { size: arr.size.toBigInt(), pricePerDay: arrayBigNumberToBigInt(arr.pricePerDay), unixDate: arrayBigNumberToBigInt(arr.unixDate) };
方式三:按业务单位格式化
如果是以太坊的 wei 等单位,用formatUnits()转换为可读的数值字符串:
import { formatUnits } from "ethers/lib/utils"; function formatBigNumberArray(arr: BigNumber[], unit: string = "wei"): string[] { return arr.map(element => formatUnits(element, unit)); } // 示例:转换为以太币单位 const newObj = { size: arr.size.toNumber(), pricePerDay: formatBigNumberArray(arr.pricePerDay, "ether"), unixDate: arrayBigNumberToNumber(arr.unixDate) // 时间戳一般不会超过安全整数 };
内容的提问来源于stack exchange,提问作者Potion
相关产品推荐
相关产品推荐

