让数值格式化成可读性最佳的字符串 | smart-unit 2.1+ ! 支持链式单位+国际化

3 阅读7分钟

痛点:现有方案的局限

在 JavaScript 项目中处理单位转换时,你是否遇到过这样的困扰?

方案一:专用库

  • bytes 只能处理文件大小
  • filesize 同样局限
  • 需要格式化时间、长度、货币?再装一个库

方案二:通用转换库

  • 每个转换都要手动定义
  • 代码臃肿,配置繁琐
// 老方式:繁琐且不灵活
const bytes = require('bytes')
const filesize = require('filesize')
// 时间、长度、货币还需要别的库...

如果只需要定义一次单位链,就能获得智能格式化、链式展示、国际化支持和简洁的 API,会怎样?


解决方案:smart-unit 2.1.2

smart-unit 是一个轻量级的 TypeScript 优先库,提供自动单位选择的单位转换功能。专为追求优雅而不牺牲功能的开发者设计。

npm install smart-unit

核心概念:简洁而强大

smart-unit 的精髓在于声明式单位链定义。只需定义一次单位和转换比例,剩下的交给库来处理。

文件大小格式化

import SmartUnit from 'smart-unit'

const fileSize = new SmartUnit(['B', 'KB', 'MB', 'GB', 'TB'], {
  baseDigit: 1024,
})

console.log(fileSize.format(1024))        // "1KB"
console.log(fileSize.format(1536))        // "1.5KB"
console.log(fileSize.format(1024 * 1024 * 100))  // "100MB"
console.log(fileSize.format(1024 * 1024 * 1024 * 5))  // "5GB"

注意 format(1536) 自动选择了 "1.5KB" 而不是 "1536B""0.0015MB"。库会智能选择最易读的单位。

长度单位(可变比例)

并非所有单位系统都使用一致的基数。公制长度单位的比例各不相同:

const length = new SmartUnit(['mm', 10, 'cm', 100, 'm', 1000, 'km'])

console.log(length.format(1500))      // "1.5m"
console.log(length.format(1500000))   // "1.5km"
console.log(length.format(25))        // "2.5cm"

通过指定单独的比例(101001000),可以准确建模任何单位层级。


双向转换:解析与格式化

smart-unit 不仅用于展示,还能将格式化字符串解析回基础值:

const time = new SmartUnit(['ms', 1000, 's', 60, 'm', 60, 'h'])

console.log(time.parse('90s'))   // 90000 (ms)
console.log(time.parse('2.5h'))  // 9000000 (ms)
console.log(time.parse('30m'))   // 1800000 (ms)

这种双向能力使其非常适合配置文件、用户输入和数据序列化。


小数位数控制

支持固定小数位或范围格式,灵活控制输出精度:

const size = new SmartUnit(['B', 'KB', 'MB', 'GB'], {
  baseDigit: 1024,
  fractionDigits: '0-2'  // 最少0位,最多2位
})

size.format(1536)        // "1.5KB"  (自动省略末尾0)
size.format(1000)        // "1000B"  (不需要小数)
size.format(1536.789)    // "1.50KB"  (最多2位小数,补0到最少位数)

链式格式化:2.0 新特性

将时间、角度等复合单位格式化为人类友好的链式表达:

const time = new SmartUnit(['ms', 1000, 's', 60, 'm', 60, 'h'])

time.formatChain(63000)      // "1m3s"
time.formatChain(3663000)    // "1h1m3s"
time.formatChain(90061000)   // "25h1m1s" (超过24小时不转换为天)

// 反向解析
time.parseChain('1h30m')     // 5400000 (ms)
time.parseChain('2h30m30s')  // 9030000 (ms)

支持自定义分隔符:

const timeWithSpace = new SmartUnit(['ms', 1000, 's', 60, 'm', 60, 'h'], {
  separator: ' '
})

timeWithSpace.formatChain(3663000)  // "1h 1m 3s"

国际化 (i18n):2.0 新特性

通过 withConvert() 方法轻松实现单位名称的本地化:

const i18nMap = {
  ms: '毫秒',
  s: '秒',
  m: '分钟',
  h: '小时',
}
const t = (unit) => i18nMap[unit]

const timeI18n = new SmartUnit(['ms', 1000, 's', 60, 'm', 60, 'h'], {
  separator: ' '
}).withConvert(t)

timeI18n.format(90000)       // "1.5分钟"
timeI18n.formatChain(90000)  // "1分钟 30秒"

配合 separator 选项,可以生成完全本地化的输出。


高精度模式:突破 JavaScript 极限

JavaScript 的 number 类型安全整数上限是 2^53 - 1(约 9 千万亿)。对于金融计算或科学应用,这是致命缺陷。

smart-unit 2.0 将高精度功能拆分为独立模块,通过 SmartUnitPrecision 类实现任意精度运算:

import { SmartUnitPrecision } from 'smart-unit/precision'

const bigLength = new SmartUnitPrecision(
  ['mm', 10, 'cm', 100, 'm', 1000, 'km', 1000, 'Mm', 1000, 'Gm', 1000, 'Tm']
)

// 支持 BigInt 和超出 JS 安全整数范围的数值
bigLength.format(10n ** 18n)  // "1000Tm"
bigLength.format('1000000000000000000')  // "1Tm"

金融计算

货币和金融数据经常超出安全整数限制,同时需要精确的十进制处理:

const currency = new SmartUnitPrecision(['', 'K', 'M', 'B', 'T'], {
  baseDigit: 1000,
  fractionDigits: 2,
})

currency.format('12345678901234567890')  // "12345678.90T"

fractionDigits: 2 确保货币值保持一致的十进制位数。

自定义 Decimal.js 配置

2.0 支持为每个实例配置独立的 Decimal.js 参数:

const precise = new SmartUnitPrecision(['m', 1000, 'km'], {
  decimalOptions: {
    precision: 50,  // 50位精度
    rounding: 4,    // 四舍五入模式
  }
})

对比优势

特性bytesfilesizesmart-unit
文件大小
自定义单位
双向转换
链式格式化
国际化
高精度
BigInt 支持
小数范围控制
TypeScript部分部分✅ 原生支持
包体积~1KB~2KB~2KB(核心)

smart-unit 用专用库的体积,提供通用库的灵活性。

测试覆盖

项目包含 100+ 条单元测试,覆盖各种边界情况:

  • BigInt 输入处理
  • Decimal.js 高精度计算
  • 链式格式化与解析
  • 国际化转换
  • 边界值和异常处理
  • 多种单位链配置

确保在生产环境中的稳定性和可靠性。


实际应用场景

数据传输速率

const bitrate = new SmartUnit(['bps', 'Kbps', 'Mbps', 'Gbps'], {
  baseDigit: 1000,
  fractionDigits: 1,
})

bitrate.format(1500000)  // "1.5Mbps"

频率

const freq = new SmartUnit(['Hz', 'kHz', 'MHz', 'GHz'], {
  baseDigit: 1000,
  fractionDigits: 2,
})

freq.format(2400000000)  // "2.40GHz"

存储容量(自定义阈值)

const storage = new SmartUnit(['B', 'KB', 'MB', 'GB', 'TB'], {
  baseDigit: 1024,
  threshold: 0.9,  // 在下一单位的 90% 时切换
})

视频时长显示

const duration = new SmartUnit(['s', 60, 'm', 60, 'h'], {
  separator: ':'
})

duration.formatChain(3661)  // "1h:1m:1s"

TypeScript 原生设计

smart-unit 使用 TypeScript 编写,提供完整的类型安全:

import SmartUnit, { type GetUnitNames } from 'smart-unit'
import type { Decimal } from 'decimal.js'

// 普通模式 - 返回 number
const regular = new SmartUnit(['B', 'KB', 'MB', 'GB'], { baseDigit: 1024 })
const num: number = regular.parse('1KB')

// 高精度模式 - 返回 Decimal
const precise = new SmartUnitPrecision(['B', 'KB', 'MB', 'GB'], { baseDigit: 1024 })
const dec: Decimal = precise.parse('1KB')

// 类型推导
const time = new SmartUnit(['ms', 1000, 's', 60, 'm', 60, 'h'])
type TimeUnits = GetUnitNames<typeof time>  // "ms" | "s" | "m" | "h"

// 国际化函数类型安全
const timeI18n = time.withConvert((unit: TimeUnits) => {
  const map = { ms: '毫秒', s: '秒', m: '分钟', h: '小时' }
  return map[unit]
})

类型推断无缝工作,API 设计有意保持简洁,降低认知负担。


快速开始

npm install smart-unit
import SmartUnit from 'smart-unit'

// 定义一次,随处使用
const size = new SmartUnit(['B', 'KB', 'MB', 'GB'], { baseDigit: 1024 })

size.format(1024 * 1024 * 100)  // "100MB"
size.parse('2.5GB')             // 2684354560

在线体验

直接在浏览器中体验 smart-unit:


总结

smart-unit 2.1.2 用优雅的方案解决了普遍存在的问题。无论是格式化文件上传、解析用户输入、处理金融数据,还是构建科学应用,它都在简洁性和功能性之间取得了完美平衡。

核心要点:

  • 用极简语法定义任意单位链
  • 自动选择最优单位
  • 双向转换(格式化和解析)
  • 链式格式化(2.0 新增)
  • 国际化支持(2.0 新增)
  • 高精度模式支持 BigInt,模块化按需加载
  • 小数位数范围控制
  • TypeScript 原生,包体积最小
  • 100+ 条单元测试全覆盖,稳定性有保障

在下一个项目中试试看,你的单位转换代码会感谢你的。


相关链接: