money-safe
v0.1.0TYPE-SAFE MONEY
DOCS INTERFACE · GUIDE / RECIPES / REFERENCE · MINOR UNITS STAY EXPLICIT
Getting Started

Getting Started

money-safe represents money with a small value shape:

ts
{
  amountMinor: 1999,
  currency: 'CNY',
  minorUnit: 2
}

For CNY, this means 19.99. For JPY, a minor unit of 0 means 1999 is 1999 JPY.

Install

bash
pnpm add @crapthings/money-safe

Use decimal strings at input boundaries

ts
import { amount } from '@crapthings/money-safe';

const value = amount('19.99', 'CNY');

value.toDecimal();
// '19.99'

Use minor units at infrastructure boundaries

ts
const value = amount.minor(1999, 'CNY');

value.toDecimal();
// '19.99'

This is the shape most payment providers, ledgers, and database rows should use.

Chain common operations

ts
const total = amount('19.99', 'CNY')
  .times(3)
  .minus('5.00')
  .plusMinor(1200);

total.toDecimal();
// '66.97'

Send stable payloads across services

ts
const paymentPayload = total.toJSON();

paymentPayload;
// { amountMinor: '6697', currency: 'CNY', minorUnit: 2 }

amountMinor is serialized as a string so JSON does not force large values through JavaScript Number.

Keep large values exact

ts
const balance = amount.bigint('900719925474099.93', 'USD');

balance.toMinor();
// 90071992547409993n

Convert existing numbers deliberately

ts
const legacy = amount.fromNumber(19.995, 'USD', {
  rounding: 'half-up'
});

legacy.toDecimal();
// '20.00'

fromNumber is for integration boundaries where another system already gives you a JavaScript number.