Skip to content

Basic Usage

Construct decimal values with a currency definition. Coins stores minor units internally and never accepts implicit floating-point input.

ts
import { USD, add, money, toDecimal } from '@vielzeug/coins';

const subtotal = add(money('12.50', USD), money('7.25', USD));

console.log(toDecimal(subtotal)); // '19.75'

Use bigint only when data is already in minor units:

ts
import { USD, money } from '@vielzeug/coins';

const cents = money(1999n, USD, { unit: 'minor' });

Define Currencies

Use built-in currency definitions for supported ISO currencies. Define a currency explicitly when your domain has a distinct scale.

ts
import { EUR, USD, defineCurrency, money } from '@vielzeug/coins';

const rewards = defineCurrency({ code: 'PTS', minorUnit: 0 });

money('10.00', USD);
money('10.00', EUR);
money('500', rewards);

Apply Exact Arithmetic

Pass decimal strings to scaling operations. Use named rounding whenever an operation can produce fractional minor units.

ts
import { USD, divide, money, multiply, round, toDecimal } from '@vielzeug/coins';

const subtotal = money('19.99', USD);
const taxed = multiply(subtotal, '1.08', { rounding: 'halfEven' });

// Extra currency precision must name its rounding policy.
const roundedInput = money('19.999', USD, { rounding: 'halfAwayFromZero' });
const split = divide(taxed, '3', { rounding: 'floor' });
const displayed = round(taxed, { fractionDigits: 0, rounding: 'halfAwayFromZero' });

console.log(toDecimal(split), toDecimal(displayed));

Aggregate and Allocate

sum receives currency context, so empty collections produce a useful zero. allocate preserves every minor unit.

ts
import { USD, allocate, money, sum, toDecimal } from '@vielzeug/coins';

const total = sum([], { currency: USD });
const weighted = allocate(money('10.00', USD), ['1', '2', '1']);
const even = allocate(money(5n, USD, { unit: 'minor' }), 2);

console.log(toDecimal(total));
console.log(weighted.map(toDecimal));
console.log(even.map((value) => value.amount)); // [3n, 2n]

Convert Currency

Create a typed rate from currency definitions and an exact decimal string.

ts
import { EUR, USD, exchange, exchangeRate, format, money } from '@vielzeug/coins';

const usdToEur = exchangeRate({ from: USD, to: EUR, value: '0.9234' });
const euros = exchange(money('100.00', USD), usdToEur, { rounding: 'halfEven' });

console.log(format(euros, { locale: 'de-DE' }));

Serialize Money

Use JSON helpers at storage and transport boundaries. Parsing validates the shape, unit, and currency code.

ts
import { USD, money, parseMoneyJSON, toJSON } from '@vielzeug/coins';

const encoded = toJSON(money('19.99', USD));
const restored = parseMoneyJSON(encoded);

// Custom currencies require an explicit resolver at restore time.
const custom = parseMoneyJSON(customEncoded, { currency: resolveAppCurrency });

Handle Errors

Use CoinsError.code for stable recovery branches.

ts
import { CoinsError, USD, money } from '@vielzeug/coins';

try {
  money(1999n, USD);
} catch (error) {
  if (error instanceof CoinsError && error.code === 'INVALID_MONEY') {
    console.log('Use { unit: \'minor\' } for bigint amounts.');
  }
}

Best Practices

  • Use decimal strings for exact external inputs.
  • Use bigint only with { unit: 'minor' }.
  • Pass named rounding options for division, scaling, and exchange.
  • Keep currency definitions at application boundaries.
  • Use sum(values, { currency }) for possibly empty collections.
  • Serialize with toJSON and validate with parseMoneyJSON.
  • Format only at presentation boundaries.