Skip to content

An experimental safe manipulate currency in typescript

Notifications You must be signed in to change notification settings

nand-industries/okane

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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.

Installation

bun add @nand.computer/okane

Quick example

import { 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 error

Getting Started

Create a Money instance using minor units:

import { okane, USD } from "okane";
const price = okane(9999n, USD); // $99.99

Arithmetic 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 error

Multiplication 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 parts

Money 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.99

Parsing 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); // 1234n

Money 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.

Todo

  • lazy evaluate for chained operations
  • Streaming sum for very large arrays
  • Rounding Strategies Plugin

About

An experimental safe manipulate currency in typescript

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • TypeScript 100.0%