@ktx-crypto/format
v1.0.3
Published
Crypto formatting utilities via composition
Readme
KTX Format
相之前这种单函数 + options 对象的轮子:
export function formatCryptoPriceV2(
price: number | string,
options: {
isProfit?: boolean;
useLargeNumberAbbr?: boolean;
prefix?: string;
suffix?: string;
forceZeroCount?: boolean;
} = {}
): string {}它的主要劣势是:
- 所有能力都堆在一个函数入口里,调用点会越来越重
options会不断膨胀,新加规则就要继续扩字段- 很多格式规则只能靠布尔开关表达,组合关系不够直观
- 类型最终会收敛成一个越来越大的 options 接口,不如原子组合清晰
在 @ktx-crypto/format 设计中,鼓励显式声明每一项格式化规则,而不是依赖隐式的默认配置。 这意味着,你应该明确告诉 formatter 你想要应用什么样的格式规则,而不是依赖隐藏在实现内部的不透明“智能默认”。
例子:
// 不推荐之前的写法(隐式默认):
const formatPrice = formatCryptoPriceV2(price); // 完全不知道最终结果
// 推荐(显式声明所需规则):
const formatPrice = buildFormat( // 语义清晰,可读性更强
withUnit('USDT'),
withThousands(),
fixPrecision(2),
)这样做的好处是:
- 业务代码更具自解释性,减少“意外惊喜”
- 可读性更强,每个能力可定向查看和测试
- 不会因为将来的默认策略变化导致老代码语义漂移
结论:KTX Format 不会为格式规则设置“自动默认”,每一项都要求你手动、显式声明,明确哪一环节做了哪些格式处理。
这也是 KTX Format 改成 buildFormat(...fns)(value) 的原因:把“格式规则定义”和“值的消费时机”拆开,把每个能力拆成可组合、可复用、可测试的原子组合 formatter 更贴近业务语义,也更容易长期演进。
KTX Format 是一套 data-last 风格的数字格式化工具。你先组合一组格式化规则,再在真正使用时传入 value:
const formatter = buildFormat(...fns) // 先组合格式化规则(函数)
const output = formatter(value) // 真正使用时再传入待格式化值它的目标很简单:
- 让格式化规则可复用
- 让多个格式化函数能自由组合
- 让最终输出不依赖外部书写顺序
- 保留原始值,便于后续扩展复杂逻辑
快速开始
import {
buildFormat,
fixPrecision,
showExplicitSign,
withSuffix,
withThousands,
withUnit,
} from '@ktx-crypto/format'
const formatPrice = buildFormat(
withUnit('USDT'),
showExplicitSign(),
withThousands(),
fixPrecision(2),
)
formatPrice(12002.1999)
// => "+12,002.20 USDT"核心用法
1. buildFormat 只支持 data-last
buildFormat(...fns)(value)2. formatter 可复用
const formatAmount = buildFormat(withThousands(), fixPrecision(2), withUnit('USDT'))
formatAmount(12002.1999)
// => "12,002.20 USDT"
formatAmount(88.1)
// => "88.10 USDT"3. 命名建议
buildFormat 的返回值本质上不是一个临时函数,而是一个有明确业务职责的 formatter。
因此,变量名建议直接体现业务语义,而不是写成泛化命名:
推荐:
const formatPrice = buildFormat(...)
const formatAmount = buildFormat(...)
const formatPnL = buildFormat(...)
const formatFundingRate = buildFormat(...)不推荐:
const formatter = buildFormat(...)
const fn = buildFormat(...)
const format = buildFormat(...)这样做的好处是:
- 看到变量名就知道它处理的业务含义
- 在组件、hooks、store、utils 中更容易复用
- 同一个页面里存在多个 formatter 时不容易混淆
4. Vue 和 React 的使用方法
在 Vue 项目中使用
配合 computed 使用:
import { computed } from 'vue'
import { buildFormat, withUnit } from '@ktx-crypto/format'
const formatAmount = buildFormat(withUnit('CNY'))
const formattedAmount = computed(() => formatAmount(amount.value))在 React 项目中使用
在 React 中完全等价用法。你可以直接在组件里引入 formatter 并在渲染时使用:
import { buildFormat, fixPrecision, withThousands, withUnit } from '@ktx-crypto/format'
const formatPrice = buildFormat(withThousands(), fixPrecision(2), withUnit('USDT'))
export function Price({ value }: { value: number }) {
return <span>{formatPrice(value)}</span>
}⚡ 编写并组合 formatter 的思路,在 Vue 和 React 等框架之间可以无缝迁移,因为它是纯函数组合,不依赖任何框架 API。
API 一览
buildFormat(...fns)
把多个格式化函数组合成一个 formatter。
const formatter = buildFormat(...fns)
const output = formatter(value)fixPrecision(precision)
控制小数位数。
buildFormat(fixPrecision(2))(12.3456)
// => "12.35"withThousands()
为普通数字结果添加千分位。
buildFormat(withThousands(), fixPrecision(2))(12002.1999)
// => "12,002.20"showExplicitSign()
为正数显式添加 +,负数保持 -,0 不加 +。
buildFormat(showExplicitSign(), fixPrecision(2))(12.3)
// => "+12.30"withPrefix(prefix)
给结果最前面加前缀。
buildFormat(withPrefix('约 '), fixPrecision(2))(12.3)
// => "约 12.30"withSuffix(suffix)
给结果最后面加后缀,并且紧贴前面的数值内容,不自动补空格。
buildFormat(withSuffix('%'), fixPrecision(2))(12.3)
// => "12.30%"如果同时和 withUnit() 一起使用,顺序会是“数值 -> suffix -> unit”:
buildFormat(fixPrecision(2), withSuffix('%'), withUnit('APR'))(12.3)
// => "12.30% APR"withUnit(unit)
把单位追加到结果后面,并始终自动补一个前置空格。
buildFormat(withUnit('USDT'), fixPrecision(2))(12.3)
// => "12.30 USDT"例如:
buildFormat(formatAbbr(), withUnit('USDT'))(1234)
// => "1.23K USDT"
buildFormat(formatAbbr(true), withUnit('CNY'))(123456789)
// => "1.23亿 CNY"withFallback(fallback)
当输入是 undefined、null、空字符串或非法数字时,返回 fallback。
buildFormat(withFallback('--'))(undefined)
// => "--"formatAbbr(isCN?)
数字缩写。
buildFormat(formatAbbr())(1234567)
// => "1.23M"
buildFormat(formatAbbr(true))(123456789)
// => "1.23亿"formatAbbr()或formatAbbr(false):国际化缩写,K / M / B / TformatAbbr(true):中文缩写,万 / 亿 / 万亿
如果同时搭配 fixPrecision(),精度会应用在缩写后的值上:
buildFormat(formatAbbr(), fixPrecision(1))(1234567890)
// => "1.2B"formatCompactZeros(threshold)
把很长的前导小数零压缩成紧凑形式。
buildFormat(formatCompactZeros(5))(0.00000123)
// => "0.0{5}123"含义是:当小数点后、首个非零数字前的连续 0 个数大于等于 threshold 时,使用压缩表示。
buildFormat(formatCompactZeros(5))(0.00000123)
// => "0.0{5}123"
buildFormat(formatCompactZeros(6))(0.00000123)
// => "0.00000123"常见组合
金额展示
const formatPrice = buildFormat(
showExplicitSign(),
withThousands(),
fixPrecision(2),
withUnit('USDT'),
)
formatPrice(12002.1999)
// => "+12,002.20 USDT"缩写金额
const formatCompactAmount = buildFormat(
withPrefix('≈ '),
showExplicitSign(),
formatAbbr(),
fixPrecision(1),
withSuffix('%'),
withUnit('USDT'),
)
formatCompactAmount(1234567)
// => "≈ +1.2M% USDT"中文缩写金额
const formatCnAmount = buildFormat(
showExplicitSign(),
formatAbbr(true),
fixPrecision(2),
withUnit('CNY'),
)
formatCnAmount(123456789)
// => "+1.23亿 CNY"百分比展示
const formatFundingRate = buildFormat(
showExplicitSign(),
fixPrecision(2),
withSuffix('%'),
)
formatFundingRate(12.3)
// => "+12.30%"极小值展示
const formatTinyPrice = buildFormat(
withPrefix('价格 '),
formatCompactZeros(4),
showExplicitSign(),
withUnit('BTC'),
)
formatTinyPrice(0.0000123)
// => "价格 +0.0{4}123 BTC"