You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用sinclair/typebox时Number()无法正确转换Oracle数据库返回的浮点数问题求助

使用sinclair/typebox时Number()无法正确转换Oracle数据库返回的浮点数问题求助

这个问题本质是JavaScript原生Number的浮点数精度限制导致的——Oracle返回的数值在转成JS Number时出现了精度溢出,和TypeBox本身关系不大,但我们可以结合TypeBox的特性来优雅解决。给你几个实用的方案:


方案1:从数据库查询阶段直接处理精度

最省心的方式是让Oracle返回精确格式化后的数值,避免前端处理麻烦。可以在SQL里用ROUND或者TO_CHAR函数控制小数位数:

-- 直接四舍五入到两位小数
SELECT ROUND(itemBalance, 2) AS itemBalance FROM your_table;

-- 或者先转成指定格式的字符串再转回数值,确保精度
SELECT TO_NUMBER(TO_CHAR(itemBalance, 'FM999999999.99')) AS itemBalance FROM your_table;

这样数据库返回的就是精确到两位小数的数值,转成JS Number后不会出现精度偏差。


方案2:在TypeBox中自定义转换逻辑处理精度

TypeBox支持通过Type.Transform添加数据转换规则,我们可以定义一个带精度处理的自定义Number类型,自动修正数值:

import { Type, Static, Transform } from '@sinclair/typebox';

// 自定义一个默认处理两位小数的Number类型
const Decimal2 = Transform(Type.Number())
  .Decode((value) => Number(value.toFixed(2)))
  .Encode((value) => value);

// 替换原Schema里的Type.Number()
export const ItemValue = Type.Object({
  itemBalance: Decimal2
})

export type ItemValueType = Static<typeof ItemValue>;

这样当数据从数据库返回后,TypeBox会自动把数值四舍五入到指定小数位,完美解决精度问题。


方案3:改用Decimal类替代原生Number(适合高精度场景)

如果是金融类对精度要求极高的项目,建议直接用decimal.js这类专门处理高精度数值的库,从根源上规避浮点数问题。同时可以在TypeBox中定义对应的类型:

import { Type, Static } from '@sinclair/typebox';
import Decimal from 'decimal.js';

// 自定义Decimal类型
const DecimalType = Type.Unsafe<Decimal>();

export const ItemValue = Type.Object({
  itemBalance: DecimalType
})

export type ItemValueType = Static<typeof ItemValue>;

// 查询时直接将数据库返回值转为Decimal实例
const result = await connection.execute(query, {}, { outFormat: OUT_FORMAT_OBJECT });
const itemValue: ItemValueType = {
  itemBalance: new Decimal(result.rows[0].itemBalance)
};

这种方式彻底避免了JS原生Number的精度缺陷,适合对数值准确性要求严格的场景。


临时应急方案

如果只是单个场景需要处理,也可以在拿到查询结果后手动修正:

const itemBalance = Number(result.rows[0].itemBalance.toFixed(2));

不过这种方式不够优雅,还是推荐前面的方案1或方案2。

备注:内容来源于stack exchange,提问作者Toseef Zafar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.20 07:58:14