okane provides immutable money objects using bigint in minor units, ensuring exact
financial calculations without floating-point errors. Each Money object combines an
amount and a currency type, enabling type-safe arithmetic and preventing mixing of
currencies.
bun add @nand.computer/okaneimport { okane, USD, EUR, fixedFx } from "okane";
// create and operate
const total = okane(9999n, USD).add(okane(9999n, USD).mul(0.23)).sub(okane(9999n, USD).mul(0.1));
console.log(total.format("en-US")); // "$111.87"
// allocate
const [a, b, c] = okane(10000n, USD).allocate([1, 1, 1]);
console.log(a.format(), b.format(), c.format()); // "$33.34 $33.33 $33.33"
// FX
const eurTotal = total.convert(EUR, fixedFx({ USD_EUR: 0.92 }));
console.log(eurTotal.format("de-DE")); // "102,64 €"
// compile-time safety
const eur = okane(1000n, EUR);
// total.add(eur); // TS errorCreate a Money instance using minor units:
import { okane, USD } from "okane";
const price = okane(9999n, USD); // $99.99Arithmetic operations preserve immutability and type safety. Addition or subtraction requires the same currency:
const tax = okane(2500n, USD);
const total = price.add(tax); // $124.99
// price.add(okane(100n, EUR)) // compile-time errorMultiplication and division accept numbers or bigint with optional rounding modes
(half-up, half-down, floor, ceil, banker). Decimal factors use scaled
integer arithmetic to maintain precision:
price.mul(1.08); // apply 8% tax
price.div(3); // split in 3 partsMoney can be split proportionally using allocate, guaranteeing no loss due to
rounding:
okane(100n, USD).allocate([1, 1, 1]); // [$0.33, $0.33, $0.34]Currency conversion uses explicit exchange rates. Differences in decimal precision between currencies are handled automatically:
import { EUR, convertWith, fixedFx } from "okane";
const fx = fixedFx({ USD: { EUR: 0.85 } });
const eur = convertWith(price, EUR, fx); // $99.99 → €84.99Parsing from strings or numbers provides exact results. fromDecimal converts decimal
strings, fromMajor rounds floating-point numbers, and fromMinor accepts minor units:
import { fromDecimal } from "okane";
const amount = fromDecimal("12.34", USD); // 1234nMoney objects support comparisons (eq, lt, gt, isZero, isPos, isNeg) and
formatting (fmt, decimal, json). All methods return new immutable instances,
enabling chaining:
const final = price.add(tax).mul(1.08).sub(okane(500n, USD));
console.log(final.fmt()); // '$135.74'okane separates core operations from parsing, formatting, and validation. Validation
returns a Result type, allowing safe handling of untrusted data without exceptions:
import { parseMoney, unwrap } from "okane";
const m = unwrap(parseMoney({ amount: "9999", currency: { code: "USD", decimals: 2 } }));Predefined currencies cover common fiat and crypto assets, and custom currencies can
be created with currency(code, decimals, symbol). Minor unit multipliers are
accessible via minorUnits(currency).
By representing money as bigint in minor units and enforcing type safety at
compile-time, okane delivers reliable financial calculations with explicit pipelines,
immutable values, precise allocation, and clear rounding behavior, while remaining
simple to integrate in JavaScript or TypeScript projects.
- lazy evaluate for chained operations
- Streaming sum for very large arrays
- Rounding Strategies Plugin