Skip to content

金额工具 ​

基于 decimal.js 的高精度金额运算工具,彻底解决 JavaScript 浮点数精度问题(0.1 + 0.2 !== 0.3)。

安装依赖 ​

bash
pnpm add @axewo/fin-core

@axewo/fin-core 已内置 decimal.js 依赖,无需额外安装。


基础运算 ​

moneyAdd(a, b) ​

安全加法,支持数字和字符串输入。

ts
import { moneyAdd } from '@axewo/fin-core'

moneyAdd(0.1, 0.2)       // 0.3 (而不是 0.30000000000000004)
moneyAdd('100.50', 50)     // 150.5
moneyAdd(9999999.99, 0.01) // 10000000

moneySub(a, b) ​

安全减法。

ts
import { moneySub } from '@axewo/fin-core'

moneySub(1, 0.9)          // 0.1
moneySub(100.05, 0.01)    // 100.04

moneyMul(a, b) ​

安全乘法(常用于金额 × 数量、金额 × 税率)。

ts
import { moneyMul } from '@axewo/fin-core'

moneyMul(0.57, 100)       // 57
moneyMul(19.9, 100)       // 1990 (而不是 1989.9999999999998)
moneyMul('12.34', 5)      // 61.7

moneyDiv(a, b) ​

安全除法,除数为 0 时返回 0(避免 Infinity)。

ts
import { moneyDiv } from '@axewo/fin-core'

moneyDiv(100, 3)          // 33.33333333333333333333
moneyDiv(100, 0)          // 0 (安全兜底)
moneyDiv('60.50', 2)      // 30.25

取整 & 比较 ​

moneyRound(value, precision?) ​

四舍五入到指定小数位,默认保留 2 位。

ts
import { moneyRound } from '@axewo/fin-core'

moneyRound(3.14159, 2)    // 3.14
moneyRound(3.14159, 3)    // 3.142
moneyRound(2.675, 2)      // 2.68 (而不是 2.67)
moneyRound(10)             // 10

moneyFloor(value, precision?) ​

向零方向截断指定小数位,负数同样向零;不是银行家舍入。

ts
import { moneyFloor } from '@axewo/fin-core'

moneyFloor(3.149, 2)      // 3.14
moneyFloor(99.999, 2)     // 99.99

moneyCeil(value, precision?) ​

远离零方向舍入指定小数位,负数会变得更小。

ts
import { moneyCeil } from '@axewo/fin-core'

moneyCeil(3.141, 2)       // 3.15
moneyCeil(99.001, 2)      // 99.01

moneyCompare(a, b) ​

金额比较,返回值语义与 Array.sort 一致。

ts
import { moneyCompare } from '@axewo/fin-core'

moneyCompare(100, 50)     // 1  (a > b)
moneyCompare(100, 100)    // 0  (a === b)
moneyCompare(50, 100)     // -1 (a < b)

// 配合 sort 使用
prices.sort(moneyCompare)

moneyIsZero(value) ​

判断金额是否为零。

ts
import { moneyIsZero } from '@axewo/fin-core'

moneyIsZero(0)            // true
moneyIsZero('0.00')        // true
moneyIsZero(0.01)          // false

税务计算 ​

calculateTax(amount, taxRate) ​

计算税额:不含税金额 × 税率,结果四舍五入到分。

ts
import { calculateTax } from '@axewo/fin-core'

calculateTax(100, 0.13)     // 13
calculateTax(99.99, 0.06)  // 6

excludeTax(amountWithTax, taxRate) ​

从含税金额还原不含税金额:含税金额 / (1 + 税率)。

ts
import { excludeTax } from '@axewo/fin-core'

excludeTax(113, 0.13)       // 100
excludeTax(106, 0.06)       // 100

格式化 ​

formatMoney(value, options?) ​

格式化金额显示,支持千分位、货币符号、负数样式。

ts
import { formatMoney } from '@axewo/fin-core'

// 基础用法
formatMoney(1234567.89)
// → "1,234,567.89"

// 自定义小数位
formatMoney(1234567.89, { precision: 0 })
// → "1,234,568"

// 货币符号
formatMoney(12345.67, { currencySymbol: '¥' })
// → "¥12,345.67"

// 负数用括号(财务报表风格)
formatMoney(-500, { negativeStyle: 'parentheses' })
// → "(500.00)"

// 自定义分隔符(欧洲风格)
formatMoney(1234.56, {
  thousandsSeparator: ' ',
  decimalSeparator: ','
})
// → "1 234,56"

// 完整示例
formatMoney(-1234567.89, {
  precision: 2,
  currencySymbol: '¥',
  negativeStyle: 'parentheses',
})
// → "¥(1,234,567.89)"

parseMoney(value) ​

从格式化字符串还原为数字。

ts
import { parseMoney } from '@axewo/fin-core'

parseMoney('¥1,234,567.89')   // 1234567.89
parseMoney('(500.00)')        // -500
parseMoney('')                // 0
parseMoney('1 234,56')        // 123456 (注意:不支持欧洲格式自动识别)

中文大写 ​

moneyToChinese(value) ​

将数字金额转为中文大写(人民币票据标准),适用于支票、合同、凭证等场景。

ts
import { moneyToChinese } from '@axewo/fin-core'

moneyToChinese(0)                  // "零元整"
moneyToChinese(100)                // "壹佰元整"
moneyToChinese(1234567.89)         // "壹佰贰拾叁万肆仟伍佰陆拾柒元捌角玖分"
moneyToChinese(10000)              // "壹万元整"
moneyToChinese(10001)              // "壹万零壹元整"
moneyToChinese(100000000)          // "壹亿元整"
moneyToChinese(0.5)                // "零元伍角"
moneyToChinese(0.05)               // "零元零伍分"
moneyToChinese(-50.3)              // "负伍拾元叁角"
moneyToChinese('1000000000.01')    // "壹十亿零壹分"

转换规则(票据标准):

场景规则
整数为零"零元整"
整数部分以万、亿分节,每节四位
节内跳零补一个"零"(10001 → 壹万零壹)
小数部分最多保留 2 位,超出四舍五入
有角无分不补"零",只写角
无角有分角位补"零"(零元零X分)
无小数末尾加"整"
负数前缀加"负"

类型签名 ​

ts
function moneyAdd(a: number | string, b: number | string): number
function moneySub(a: number | string, b: number | string): number
function moneyMul(a: number | string, b: number | string): number
function moneyDiv(a: number | string, b: number | string): number

function moneyRound(value: number | string, precision?: number): number
function moneyFloor(value: number | string, precision?: number): number
function moneyCeil(value: number | string, precision?: number): number

function moneyCompare(a: number | string, b: number | string): -1 | 0 | 1
function moneyIsZero(value: number | string): boolean

function calculateTax(amount: number | string, taxRate: number | string): number
function excludeTax(amountWithTax: number | string, taxRate: number | string): number

function formatMoney(
  value: number | string,
  options?: {
    precision?: number             // 默认 2
    thousandsSeparator?: string    // 默认 ','
    decimalSeparator?: string      // 默认 '.'
    currencySymbol?: string        // 默认 ''
    negativeStyle?: 'minus' | 'parentheses'  // 默认 'minus'
  }
): string

function parseMoney(value: string): number

function moneyToChinese(value: number | string): string