Skip to content
VersionSize

exchange

Converts money from one currency to another using the provided exchange rate. Maintains precision by using bigint arithmetic.

Implementation

View Source Code
ts
import type { Money } from './types';

/**
 * Exchange rate for currency conversion.
 */
export type ExchangeRate = {
  from: string; // Source currency code
  to: string; // Target currency code
  rate: number; // Exchange rate multiplier
};

/**
 * Converts money from one currency to another using the provided exchange rate.
 * Maintains precision by using bigint arithmetic.
 *
 * @example
 * ```ts
 * const usd = { amount: 100000n, currency: 'USD' }; // $1,000.00
 * const rate = { from: 'USD', to: 'EUR', rate: 0.85 };
 *
 * exchange(usd, rate);
 * // { amount: 85000n, currency: 'EUR' } // €850.00
 * ```
 *
 * @param money - Money to convert
 * @param rate - Exchange rate information
 * @returns Converted money in target currency
 * @throws {Error} If source currency doesn't match rate.from
 */
export function exchange(money: Money, rate: ExchangeRate): Money {
  if (money.currency !== rate.from) {
    throw new Error(`Currency mismatch: expected ${rate.from}, got ${money.currency}`);
  }

  // Convert rate to avoid floating point issues
  // Multiply by 1000000 for precision, then divide back
  const rateBigInt = BigInt(Math.round(rate.rate * 1000000));
  const convertedAmount = (money.amount * rateBigInt) / 1000000n;

  return {
    amount: convertedAmount,
    currency: rate.to,
  };
}

Features

  • Precision-Safe: Uses bigint arithmetic to avoid floating-point errors
  • Currency Validation: Ensures source currency matches exchange rate
  • Type-Safe: Uses Money and ExchangeRate types
  • Flexible Rates: Accepts any exchange rate multiplier
  • Isomorphic: Works in both Browser and Node.js

API

Type Definitions
ts
/**
 * Represents a monetary amount with currency.
 * Amount is stored as bigint (minor units/cents) for precision.
 */
export type Money = {
  readonly amount: bigint; // Amount in minor units (e.g., cents for USD)
  readonly currency: string; // ISO 4217 currency code (e.g., 'USD', 'EUR')
};
ts
function exchange(money: Money, rate: ExchangeRate): Money;

Parameters

  • money: Money object to convert
    • amount: Amount in minor units (cents) as bigint
    • currency: ISO 4217 source currency code
  • rate: Exchange rate information
    • from: Source currency code (must match money.currency)
    • to: Target currency code
    • rate: Exchange rate multiplier

Returns

  • New Money object in target currency

Throws

  • Error: If source currency doesn't match rate.from

Examples

Basic Currency Conversion

ts
import { exchange } from '@vielzeug/toolkit';

const usd = { amount: 100000n, currency: 'USD' }; // $1,000.00
const rate = { from: 'USD', to: 'EUR', rate: 0.85 };

const eur = exchange(usd, rate);
// { amount: 85000n, currency: 'EUR' } // €850.00

Reverse Conversion

ts
import { exchange } from '@vielzeug/toolkit';

const eur = { amount: 85000n, currency: 'EUR' }; // €850.00
const rate = { from: 'EUR', to: 'USD', rate: 1.18 };

const usd = exchange(eur, rate);
// { amount: 100300n, currency: 'USD' } // ~$1,003.00

Real-World Example: International Purchase

ts
import { exchange, currency } from '@vielzeug/toolkit';

// Product price in USD
const productPrice = { amount: 49999n, currency: 'USD' }; // $499.99

// Current exchange rate USD -> EUR
const usdToEur = { from: 'USD', to: 'EUR', rate: 0.92 };

// Convert to EUR for European customer
const priceInEur = exchange(productPrice, usdToEur);
// { amount: 45999n, currency: 'EUR' }

console.log(`Price: ${currency(priceInEur, { locale: 'de-DE' })}`);
// Price: 459,99 €

Multi-Currency Conversion

ts
import { exchange } from '@vielzeug/toolkit';

const usd = { amount: 100000n, currency: 'USD' }; // $1,000.00

// Convert to multiple currencies
const rates = [
  { from: 'USD', to: 'EUR', rate: 0.85 },
  { from: 'USD', to: 'GBP', rate: 0.73 },
  { from: 'USD', to: 'JPY', rate: 110.0 },
];

const conversions = rates.map((rate) => ({
  currency: rate.to,
  amount: exchange(usd, rate),
}));

// EUR: { amount: 85000n, currency: 'EUR' }
// GBP: { amount: 73000n, currency: 'GBP' }
// JPY: { amount: 11000000n, currency: 'JPY' }

High Exchange Rate (to JPY)

ts
import { exchange } from '@vielzeug/toolkit';

const usd = { amount: 10000n, currency: 'USD' }; // $100.00
const rate = { from: 'USD', to: 'JPY', rate: 110.5 };

const jpy = exchange(usd, rate);
// { amount: 1105000n, currency: 'JPY' } // ¥11,050

Low Exchange Rate (from JPY)

ts
import { exchange } from '@vielzeug/toolkit';

const jpy = { amount: 1105000n, currency: 'JPY' }; // ¥11,050
const rate = { from: 'JPY', to: 'USD', rate: 0.00905 };

const usd = exchange(jpy, rate);
// { amount: 10000n, currency: 'USD' } // ~$100.00

Dynamic Exchange Rates

ts
import { exchange } from '@vielzeug/toolkit';

// Fetch current exchange rate from API
async function convertCurrency(money: Money, targetCurrency: string) {
  // Simulated API call
  const apiRate = await fetchExchangeRate(money.currency, targetCurrency);

  const rate = {
    from: money.currency,
    to: targetCurrency,
    rate: apiRate,
  };

  return exchange(money, rate);
}

// Usage
const usd = { amount: 250000n, currency: 'USD' };
const gbp = await convertCurrency(usd, 'GBP');

Currency Validation Error

ts
import { exchange } from '@vielzeug/toolkit';

const eur = { amount: 100000n, currency: 'EUR' };
const wrongRate = { from: 'USD', to: 'GBP', rate: 0.73 };

try {
  exchange(eur, wrongRate);
} catch (error) {
  console.error(error);
  // Error: Currency mismatch: expected USD, got EUR
}

Chain Conversions

ts
import { exchange } from '@vielzeug/toolkit';

// USD -> EUR -> GBP
const usd = { amount: 100000n, currency: 'USD' };

const usdToEur = { from: 'USD', to: 'EUR', rate: 0.85 };
const eur = exchange(usd, usdToEur);
// { amount: 85000n, currency: 'EUR' }

const eurToGbp = { from: 'EUR', to: 'GBP', rate: 0.86 };
const gbp = exchange(eur, eurToGbp);
// { amount: 73100n, currency: 'GBP' }

Implementation Notes

  • Precision: Uses bigint multiplication/division to maintain precision
  • Rate Multiplier: Rate of 0.85 means 1 unit of source = 0.85 units of target
  • Minor Units: Both source and target amounts are in minor units (cents)
  • Rounding: Uses integer division (truncates), may lose fractional cents
  • Rate Source: You must provide exchange rates (from API, database, etc.)
  • Currency Validation: Always validates that source currency matches rate.from
  • Negative Amounts: Handles negative amounts correctly
  • Precision Factor: Internally uses 6 decimal places for rate precision

See Also