Number Formatting

Configure number formatting with the type-friendly IFormat object — thousands separators, percent, compact notation, and rounding all in one place.

Number Formatting

Formatting is configured via an IFormat object, accepted in three places:

  • fmt(value, format) — direct formatting
  • calc(expr, { ..., _fmt }) — format the expression result
  • Chain terminator chainAdd(...)(format)

Every field has full type hints and autocompletion — typos are caught at compile time.

fmt
(1234.5, {
decimals
: 2,
thousands
: true }) // "1,234.50"
calc
('9.9 * 3', {
_fmt
: {
decimals
: 2 } }) // "29.70"
chainAdd
(1000, 2000)({
decimals
: 2,
thousands
: 'eu' }) // "3.000,00"

Full field reference

FieldTypeDescription
decimalsnumber | { min?, max? }Decimal places (default: preserve original):
• number = fixed N places, zero-padded (2"1.00")
{ max } = at most N places, excess truncated, no zero-padding
{ min } = at least N places, zero-padded
rounding'truncate' | 'halfUp' | 'banker' | 'ceil' | 'floor' | 'expand'
'trunc' | 'round' | 'halfEven'
Rounding strategy used with decimals, default 'truncate':
halfUp / round — round half up
banker / halfEven — banker's rounding (round half to even)
ceil / floor — toward +∞ / -∞ (like Math)
expand — away from zero
See below
thousandsboolean | 'us' | 'eu' | 'in'Thousands grouping (default: none):
true = US style 1,234.50
'eu' = European 1.234,50
'in' = Indian 1,23,456
compactboolean | 'zh'Compact notation (default: none):
true = K/M/B/T (1.23M)
'zh' = 万/亿 (123.45万)
clamp[min, max]Clamp result to range:
values below min become min, above max become max
(applied before formatting)
output'percent' | 'fraction' | 'scientific' | 'number'
(or token %% // e num)
Output form, mutually exclusive:
percent — multiply by 100 and append %
fraction — simplest fraction
scientific — scientific notation
number — return a number (all others return string)
plusbooleanPrepend + to positive numbers
(negatives and zero are unaffected)
padnumberLeft-pad the integer part with zeros to N digits
(5 with pad: 3"005", decimal part unaffected)

Decimal places decimals

A number means fixed places (zero-padded); an object means a range (max = at most, min = at least):

fmt
(0.1234, {
decimals
: 2 }) // "0.12" fixed 2 places
fmt
(1.1, {
decimals
: {
max
: 2 } }) // "1.1" at most 2, no zero-padding
fmt
(1, {
decimals
: {
min
: 2 } }) // "1.00" at least 2 places
fmt
(1.2345, {
decimals
: {
min
: 1,
max
: 3 } }) // "1.234"

Rounding rounding

Default is truncate (toward zero, no precision loss). Each strategy has a JS-style alias — use whichever is easier to remember:

ValueJS aliasMeaning
'truncate''trunc'Truncate toward zero (same as Math.trunc), default
'halfUp''round'Round half up (same as Math.round)
'banker''halfEven'Banker's rounding: round half to even (same as Intl.NumberFormat with roundingMode: 'halfEven')
'ceil'Round toward +∞ (same as Math.ceil)
'floor'Round toward -∞ (same as Math.floor)
'expand'Round away from zero

The three directional modes differ only for negative values (-1.1ceil -1, floor -2, expand -2). For positive values they coincide with rounding up.

fmt
(1.235, {
decimals
: 2 }) // "1.23" default truncate
fmt
(1.235, {
decimals
: 2,
rounding
: 'round' }) // "1.24" round half up
fmt
(2.5, {
decimals
: 0,
rounding
: 'halfEven' }) // "2" banker's: round to even
fmt
(3.5, {
decimals
: 0,
rounding
: 'halfEven' }) // "4" round to even
fmt
(-1.001, {
decimals
: 0,
rounding
: 'ceil' }) // "-1" toward +∞
fmt
(-1.001, {
decimals
: 0,
rounding
: 'floor' }) // "-2" toward -∞
fmt
(-1.001, {
decimals
: 0,
rounding
: 'expand' }) // "-2" away from zero
Note: JS's Number.prototype.toFixed is not banker's rounding (it approximates round-half-up and has floating-point bugs, e.g. (1.005).toFixed(2)"1.00"). Use 'banker' / 'halfEven' for true banker's rounding.

Thousands separator thousands

true = US style; or specify a locale preset:

fmt
(1234.5, {
decimals
: 2,
thousands
: true }) // "1,234.50" (US)
fmt
(1234.5, {
decimals
: 2,
thousands
: 'eu' }) // "1.234,50" (European)
fmt
(123456, {
thousands
: 'in' }) // "1,23,456" (Indian)

Compact notation compact

true = K/M/B/T; or 'zh' for Chinese units:

fmt
(1234567, {
decimals
: 2,
compact
: true }) // "1.23M"
fmt
(1234567, {
decimals
: 2,
compact
: 'zh' }) // "123.45万"

Output form output

Mutually exclusive output forms — use either the readable word or the token symbol:

fmt
(0.5, {
output
: 'percent' }) // "50%" (or '%%')
fmt
(0.5, {
output
: 'fraction' }) // "1/2" (or '//')
fmt
(1000, {
output
: 'scientific' }) // "1e+3" (or 'e')
fmt
(0.1234, {
output
: 'number',
decimals
: 2 }) // 0.12 ← number type (or 'num')

Clamping clamp

Clamp the result to [min, max] — values below the lower bound become the lower bound, values above the upper bound become the upper bound. Composable with other fields:

calc
('150', {
_fmt
: {
clamp
: [0, 100] } }) // "100"
calc
('-50', {
_fmt
: {
clamp
: [0, 100] } }) // "0"
calc
('150.567', {
_fmt
: {
clamp
: [0, 100],
decimals
: 2 } }) // "100.00"

Plus sign / zero-padding

fmt
(1, {
plus
: true }) // "+1" (negatives and zero unaffected)
fmt
(5, {
pad
: 3 }) // "005"

Combining fields

Fields can be freely combined:

fmt
(1234.5, {
decimals
: 2,
thousands
: true,
rounding
: 'round',
plus
: true }) // "+1,234.50"
fmt
(12345678, {
compact
: 'zh',
decimals
: {
max
: 2 } }) // "1234.56万"

Try it live

fmt(1234567.891, { decimals: 2, thousands: true }) // "1,234,567.89"
fmt(0.1234, { output: 'percent', decimals: 1 }) // "12.3%"
fmt(1234567, { compact: 'zh', decimals: 2 }) // "123.45万"
calc('150', { _fmt: { clamp: [0, 100] } }) // "100"
在线运行⌘/Ctrl + Enter 运行