Skip to content
toneflixPublic

About

A simple and efficient money and currency conversion and formatting tool for JavaScript and TypeScript projects.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

@toneflix/money

A simple and efficient money and currency conversion and formatting tool for JavaScript and TypeScript projects. Format currency with ease, convert between currencies using live exchange rates, and chain operations elegantly.

npm version npm downloads GitHub License Run Tests

Features

  • Easy Currency Formatting - Format numbers as currency with proper symbols and formatting
  • Live Exchange Rates - Convert between currencies using real-time exchange rates
  • Exchange Rate Providers - Choose between ExchangeRate-API, Frankfurter, or another compatible provider
  • Mathematical Operations - Perform calculations with proper precision (add, subtract, multiply, divide, etc.)
  • Chainable API - Fluent, intuitive method chaining for complex operations
  • TypeScript Support - Full type safety with TypeScript definitions
  • Multiple Currencies - Support for all major world currencies
  • Zero Runtime Dependencies - No external dependencies, lightweight and fast

Installation

npm install @toneflix/money
pnpm add @toneflix/money
yarn add @toneflix/money

Quick Start

Money Formatting

import { Money } from '@toneflix/money';

// Format a number as currency

Money.format(1234.56, 'USD'); // "$1,234.56"

Money.format(1234.56, 'EUR'); // "€1,234.56"

Money.format(1234.56, 'GBP'); // "£1,234.56"

// Using instance methods

const money = new Money(1234.56, 'USD');

money.format(); // "$1,234.56"

money.whole(); // "$1,234" (no decimals)

money.compact(); // "$1.2K" (compact notation)

Currency Conversion

By default, currency conversion uses ExchangeRateApi, preserving the existing Exchange.setApiKey() and EXCHANGERATE_API_KEY configuration.

import { Exchange } from '@toneflix/money';

// ExchangeRateApi is the default provider.
// Set your API key in code...

Exchange.setApiKey('your-api-key-here');

// ...or use EXCHANGERATE_API_KEY in your environment.

// Convert currency with the chainable API

const result = await Exchange.from('USD').to('EUR').convert(100);

console.log(result); // e.g., 92.5 (euros)

// Get formatted result

const formatted = await Exchange.from('USD').to('GBP').convert(100).format();

console.log(formatted); // e.g., "£85.23"

To use Frankfurter instead, select FrankfurterApi. Frankfurter does not require an API key.

import { Exchange, FrankfurterApi } from '@toneflix/money';

Exchange.setProvider(FrankfurterApi);

const result = await Exchange.from('USD').to('EUR').convert(100);

API Reference

Money Class

The Money class handles currency formatting and display.

Constructor

new Money(amount?: number | string, currency?: CurrencyCode)

Parameters:

  • amount - The monetary amount to format
  • currency - Optional currency code (e.g., 'USD', 'EUR', 'GBP')

Example:

const money = new Money(1234.56, 'USD');

Static Methods

Money.setDefaultCurrency(currency: CurrencyCode)

Set the default currency for all Money instances.

Money.setDefaultCurrency('EUR');

const money = new Money(100); // Uses EUR by default
Money.format(amount: number | string, currency?: CurrencyCode)

Format an amount as currency (static method).

Money.format(1234.56, 'USD'); // "$1,234.56"

Money.format(1234.56, 'EUR'); // "€1,234.56"

Money.format(1234.56, 'JPY'); // "¥1,234.56"
Money.whole(amount: number | string, currency?: CurrencyCode)

Format an amount without decimal places (static method).

Money.whole(1234.56, 'USD'); // "$1,234"
Money.compact(amount: number | string, currency?: CurrencyCode)

Format an amount in compact notation (static method).

Money.compact(1234567, 'USD'); // "$1.2M"

Money.compact(1234, 'USD'); // "$1.2K"

Money.compact(1234567890, 'USD'); // "$1.2B"
Money.convert(amount: number | string, from: CurrencyCode, to: CurrencyCode)

Convert and format amount between currencies (static method).

const converted = await Money.convert(100, 'USD', 'EUR');

console.log(converted.format()); // e.g., "€92.50"
Money.currencyCode()

Get the default currency code.

Money.currencyCode(); // "USD"
Money.currencySymbol()

Get the default currency symbol.

Money.currencySymbol(); // "$"
Money.of(amount: number | string, currency?: CurrencyCode)

Create a new Money instance (factory method).

const money = Money.of(100, 'USD');

Instance Methods

format()

Format the amount with currency symbol and proper formatting.

const money = new Money(1234.56, 'USD');

money.format(); // "$1,234.56"
whole()

Format the amount without decimal places.

const money = new Money(1234.56, 'USD');

money.whole(); // "$1,234"
compact()

Format the amount in compact notation (K, M, B, T).

const money = new Money(1234567, 'USD');

money.compact(); // "$1.2M"
convert(to: CurrencyCode)

Convert the amount to another currency.

const money = new Money(100, 'USD');

const converted = await money.convert('EUR');

console.log(converted.format()); // e.g., "€92.50"
setNegativeStyle(style: 'minus' | 'parentheses')

Set how negative amounts should be displayed.

const money = new Money(-100, 'USD');

money.setNegativeStyle('minus');

money.format(); // "-$100.00"

money.setNegativeStyle('parentheses');

money.format(); // "($100.00)"
currencyCode()

Get the current currency code.

const money = new Money(100, 'EUR');

money.currencyCode(); // "EUR"
currencySymbol()

Get the current currency symbol.

const money = new Money(100, 'GBP');

money.currencySymbol(); // "£"
toString()

Get string representation (same as format()).

const money = new Money(100, 'USD');

money.toString() // "$100.00"
`${money}`; // "$100.00"
add(other: number | string | Money)

Add another amount to this Money instance.

const money = new Money(100, 'USD');

const result = money.add(50);

console.log(result.format()); // "$150.00"

// Can also add another Money instance

const other = new Money(25, 'USD');

money.add(other).format(); // "$125.00"
subtract(other: number | string | Money)

Subtract another amount from this Money instance.

const money = new Money(100, 'USD');

const result = money.subtract(30);

console.log(result.format()); // "$70.00"
multiply(factor: number | string | Money)

Multiply this Money instance by a factor.

const money = new Money(50, 'USD');

const result = money.multiply(3);

console.log(result.format()); // "$150.00"
divide(divisor: number | string | Money)

Divide this Money instance by a divisor.

const money = new Money(100, 'USD');

const result = money.divide(4);

console.log(result.format()); // "$25.00"
ceil()

Round this Money instance up to the nearest integer.

const money = new Money(99.45, 'USD');

const result = money.ceil();

console.log(result.format()); // "$100.00"
floor()

Round this Money instance down to the nearest integer.

const money = new Money(99.95, 'USD');

const result = money.floor();

console.log(result.format()); // "$99.00"
round(digits?: number)

Round this Money instance to specified decimal digits.

const money = new Money(99.456, 'USD');

money.round().format(); // "$99.00" (default: 0 decimals)

money.round(1).format(); // "$99.50"

money.round(2).format(); // "$99.46"
mod(divisor: number | string | Money)

Calculate modulus (remainder) of this Money instance by divisor.

const money = new Money(100, 'USD');

const result = money.mod(30);

console.log(result.format()); // "$10.00" (100 % 30 = 10)
absolute()

Get absolute value of this Money instance.

const money = new Money(-100, 'USD');

const result = money.absolute();

console.log(result.format()); // "$100.00"
share(total: number | string | Money, ratio: string | number)

Calculate share of this Money instance based on total and ratio.

const money = new Money(100, 'USD');

const result = money.share(1000, 0.1); // 10% share

console.log(result.format()); // "$10.00"

// Calculate proportional share

const part = new Money(25, 'USD');

const total = 100;

const ratio = 0.5; // 50% ratio

part.share(total, ratio).format(); // "$12.50"

Exchange Class

The Exchange class handles currency conversion with live exchange rates through a configurable exchange-rate provider.

Constructor

new Exchange(source?: CurrencyCode, target?: CurrencyCode, amount?: number)

Parameters:

  • source - Source currency code (optional)
  • target - Target currency code (optional)
  • amount - Amount to convert (optional, default: 1)

Example:

const exchange = new Exchange('USD', 'EUR', 100);

Static Methods

Exchange.setApiKey(key: string)

Set the API key used by providers that support API-key authentication.

This method is preserved for backwards compatibility. With the default ExchangeRateApi provider, the key can be configured either with Exchange.setApiKey() or the EXCHANGERATE_API_KEY environment variable.

Exchange.setApiKey('your-api-key-here');

FrankfurterApi does not require an API key, so Exchange.setApiKey() is not required when Frankfurter is selected.

Exchange.setProvider(provider)

Set the exchange-rate provider used by Exchange.

Pass the provider class itself, not an instance.

import { Exchange, ExchangeRateApi, FrankfurterApi } from '@toneflix/money';

// ExchangeRateApi preserves the existing API-key based behaviour.

Exchange.setProvider(ExchangeRateApi);

Exchange.setApiKey('your-api-key-here');

// Or switch to Frankfurter, which does not require an API key.

Exchange.setProvider(FrankfurterApi);

The configured provider is used by subsequent Exchange conversions and rate requests.

Exchange.from(currency: CurrencyCode)

Create a new Exchange instance with source currency (static method).

const exchange = Exchange.from('USD');
Exchange.to(currency: CurrencyCode)

Create a new Exchange instance with target currency (static method).

const exchange = Exchange.to('EUR');
Exchange.format(amount: number, from: CurrencyCode, to: CurrencyCode)

Convert and format amount in one call (static method).

const formatted = await Exchange.format(100, 'USD', 'EUR');

console.log(formatted); // e.g., "€92.50"

Instance Methods

from(currency: CurrencyCode)

Set the source currency.

const exchange = new Exchange();

exchange.from('USD');
to(currency: CurrencyCode)

Set the target currency.

const exchange = new Exchange();

exchange.to('EUR');
convert(amount: number, source?: CurrencyCode, target?: CurrencyCode)

Convert an amount between currencies. Returns this for chaining.

// Basic usage

const result = await exchange.convert(100);

// With optional currencies

const result = await exchange.convert(100, 'USD', 'EUR');

// Chainable

const result = await exchange.from('USD').to('EUR').convert(100);
rate(source?: CurrencyCode, target?: CurrencyCode)

Get the exchange rate between two currencies. Returns this for chaining.

// Get exchange rate

const rate = await exchange.rate('USD', 'EUR');

console.log(rate); // e.g., 0.925

// Chainable

const rate = await exchange.from('USD').to('EUR').rate();
format()

Format the converted amount with currency symbol.

const formatted = await exchange.from('USD').to('EUR').convert(100).format();

console.log(formatted); // e.g., "€92.50"

Thenable API

The Exchange class implements a "thenable" interface, making it work seamlessly with async/await and Promises:

// Methods return 'this' for chaining (synchronous)

const chain = exchange.from('USD').to('EUR').convert(100);

// Execution happens when awaited or .then() is called

const result = await chain;

// Or with .then()

chain.then((result) => {
  console.log(result); // Converted amount
});

// With error handling

chain

  .then((result) => console.log(result))

  .catch((error) => console.error(error))

  .finally(() => console.log('Done'));

How it works:

  • All methods (from(), to(), convert(), rate()) return this synchronously
  • The chain stays synchronous until you await it or call .then()
  • When awaited/then'd, it automatically executes the API call
  • This gives you full control over when the async operation happens

Exchange Rate Providers

Exchange delegates live currency conversion to a configured provider. This keeps the chainable Exchange API the same while allowing different exchange-rate services to be used.

ExchangeRateApi

ExchangeRateApi is the backwards-compatible/default provider and uses ExchangeRate-API.

It requires an API key. Existing configuration continues to work:

import { Exchange, ExchangeRateApi } from '@toneflix/money';

Exchange.setProvider(ExchangeRateApi);

// Runtime configuration

Exchange.setApiKey('your-api-key-here');

const result = await Exchange.from('USD').to('EUR').convert(100);

You can also configure the provider through the environment:

EXCHANGERATE_API_KEY=your-api-key-here

When both are available, the API key explicitly supplied through Exchange.setApiKey() is used before the provider's environment fallback.

FrankfurterApi

FrankfurterApi provides currency rates without requiring an API key.

import { Exchange, FrankfurterApi } from '@toneflix/money';

Exchange.setProvider(FrankfurterApi);

const amount = await Exchange.from('USD').to('EUR').convert(100);

const rate = await Exchange.from('USD').to('EUR').rate();

Frankfurter returns an exchange rate, and the provider derives the converted amount from that rate so the public Exchange API behaves consistently across providers.

Switching Providers

Provider selection is global to Exchange. Set the provider before creating or executing exchange operations:

import { Exchange, ExchangeRateApi, FrankfurterApi } from '@toneflix/money';

// API-key based provider

Exchange.setProvider(ExchangeRateApi);

Exchange.setApiKey('your-api-key-here');

const apiResult = await Exchange.from('USD').to('EUR').convert(100);

// Keyless provider

Exchange.setProvider(FrankfurterApi);

const frankfurterResult = await Exchange.from('USD').to('EUR').convert(100);

The rest of the API remains unchanged: from(), to(), convert(), rate(), format(), and the thenable/awaitable chain work with the selected provider.

Usage Examples

Basic Formatting

import { Money } from '@toneflix/money';

// Different currencies

console.log(Money.format(1234.56, 'USD')); // "$1,234.56"

console.log(Money.format(1234.56, 'EUR')); // "€1,234.56"

console.log(Money.format(1234.56, 'GBP')); // "£1,234.56"

console.log(Money.format(1234.56, 'JPY')); // "¥1,234.56"

// Different formats

console.log(Money.format(1234.56, 'USD')); // "$1,234.56"

console.log(Money.whole(1234.56, 'USD')); // "$1,234"

console.log(Money.compact(1234567, 'USD')); // "$1.2M"

Negative Numbers

import { Money } from '@toneflix/money';

const money = new Money(-1234.56, 'USD');

// Minus sign (default)

money.setNegativeStyle('minus');

console.log(money.format()); // "-$1,234.56"

// Parentheses (accounting style)

money.setNegativeStyle('parentheses');

console.log(money.format()); // "($1,234.56)"

Compact Notation

import { Money } from '@toneflix/money';

console.log(Money.compact(999, 'USD')); // "$999"

console.log(Money.compact(1234, 'USD')); // "$1.2K"

console.log(Money.compact(1234567, 'USD')); // "$1.2M"

console.log(Money.compact(1234567890, 'USD')); // "$1.2B"

console.log(Money.compact(1234567890123, 'USD')); // "$1.2T"

Mathematical Operations

import { Money } from '@toneflix/money';

const price = new Money(99.99, 'USD');

// Addition

const withTax = price.add(7.5);

console.log(withTax.format()); // "$107.49"

// Subtraction

const withDiscount = price.subtract(10);

console.log(withDiscount.format()); // "$89.99"

// Multiplication

const quantity = price.multiply(3);

console.log(quantity.format()); // "$299.97"

// Division

const perItem = price.divide(2);

console.log(perItem.format()); // "$49.995" or rounded

// Rounding

const rounded = price.round(2);

console.log(rounded.format()); // "$100.00"

// Chaining operations

const total = new Money(100, 'USD').add(50).multiply(2).subtract(25).round();

console.log(total.format()); // "$275.00"

// Calculate percentage/share

const amount = new Money(100, 'USD');

const tip = amount.share(100, 0.15); // 15% tip

console.log(tip.format()); // "$15.00"

// Absolute value

const debt = new Money(-50, 'USD');

console.log(debt.absolute().format()); // "$50.00"

// Modulus

const change = new Money(100, 'USD').mod(30);

console.log(change.format()); // "$10.00"

Currency Conversion

Using the default ExchangeRateApi provider:

import { Exchange } from '@toneflix/money';

Exchange.setApiKey('your-api-key-here');

// Simple conversion

const amount = await Exchange.from('USD').to('EUR').convert(100);

console.log(amount); // e.g., 92.5

// Get exchange rate

const rate = await Exchange.from('USD').to('EUR').rate();

console.log(rate); // e.g., 0.925

// Convert and format

const formatted = await Exchange.from('USD').to('GBP').convert(100).format();

console.log(formatted); // e.g., "£85.23"

Using FrankfurterApi:

import { Exchange, FrankfurterApi } from '@toneflix/money';

Exchange.setProvider(FrankfurterApi);

const amount = await Exchange.from('USD').to('EUR').convert(100);

const rate = await Exchange.from('USD').to('EUR').rate();

Combining Money and Exchange

import { Money } from '@toneflix/money';

Money.setDefaultCurrency('USD');

const money = new Money(100);

console.log(money.format()); // "$100.00"

// Convert to another currency

const converted = await money.convert('EUR');

console.log(converted.format()); // e.g., "€92.50"

// Static conversion

const result = await Money.convert(100, 'USD', 'GBP');

console.log(result.format()); // e.g., "£85.23"

Advanced Chaining

import { Exchange } from '@toneflix/money';

Exchange.setApiKey('your-api-key-here');

// Build the chain (synchronous)

const chain = Exchange.from('USD').to('EUR').convert(1000);

// Execute when ready (asynchronous)

const result = await chain;

console.log(result); // e.g., 925.0

// Or with callbacks

chain

  .then((result) => {
    console.log(`Converted: ${result}`);

    return result;
  })

  .then((result) => {
    // Chain more operations

    return result * 1.1;
  })

  .catch((error) => {
    console.error('Conversion failed:', error);
  })

  .finally(() => {
    console.log('Conversion complete');
  });

Using Environment Variables

This library has zero runtime dependencies - you don't need dotenv or any other package!

Environment-based API-key configuration applies to ExchangeRateApi. FrankfurterApi does not require an API key.

Set the ExchangeRate-API key in your preferred way:

Option 1: Using your own dotenv (if you have one)

# .env file

EXCHANGERATE_API_KEY=your-api-key-here

Option 2: System environment variables

# Terminal

export EXCHANGERATE_API_KEY=your-api-key-here

# Or in your deployment platform (Vercel, Netlify, etc.)

Option 3: Runtime configuration

import { Exchange, ExchangeRateApi } from '@toneflix/money';

Exchange.setProvider(ExchangeRateApi);

Exchange.setApiKey('your-api-key-here');

Then use it:

import { Exchange } from '@toneflix/money';

// ExchangeRateApi can resolve the key from Exchange.setApiKey()
// or its supported environment configuration.

const result = await Exchange.from('USD').to('EUR').convert(100);

If you select FrankfurterApi, no key configuration is necessary:

import { Exchange, FrankfurterApi } from '@toneflix/money';

Exchange.setProvider(FrankfurterApi);

const result = await Exchange.from('USD').to('EUR').convert(100);

Error Handling

import { Exchange } from '@toneflix/money';

try {
  const result = await Exchange.from('USD').to('EUR').convert(100);

  console.log(result);
} catch (error) {
  if (error.type === 'missing-key') {
    console.error('Please configure an API key for the selected provider');
  } else {
    console.error('Conversion error:', error.message);
  }
}

Supported Currencies

The library supports all major world currencies including but not limited to:

  • 🇺🇸 USD (US Dollar)
  • 🇪🇺 EUR (Euro)
  • 🇬🇧 GBP (British Pound)
  • 🇯🇵 JPY (Japanese Yen)
  • 🇨🇦 CAD (Canadian Dollar)
  • 🇦🇺 AUD (Australian Dollar)
  • 🇨🇭 CHF (Swiss Franc)
  • 🇨🇳 CNY (Chinese Yuan)
  • 🇮🇳 INR (Indian Rupee)
  • And many more...

See the full list in the currencies.ts file.

Provider Authentication

Authentication depends on the selected exchange-rate provider.

ExchangeRateApi

ExchangeRateApi requires an API key from ExchangeRate-API.

Getting Started:

  1. Visit exchangerate-api.com
  2. Sign up for an account
  3. Copy your API key
  4. Configure it using Exchange.setApiKey() or the supported environment variable:
import { Exchange, ExchangeRateApi } from '@toneflix/money';

Exchange.setProvider(ExchangeRateApi);

// Method 1: Set in code

Exchange.setApiKey('your-api-key-here');

// Method 2: Use environment configuration

// EXCHANGERATE_API_KEY=your-api-key-here

Existing code that only calls Exchange.setApiKey() remains compatible because ExchangeRateApi is the backwards-compatible provider.

FrankfurterApi

FrankfurterApi does not require an API key.

import { Exchange, FrankfurterApi } from '@toneflix/money';

Exchange.setProvider(FrankfurterApi);

const result = await Exchange.from('USD').to('EUR').convert(100);

No Exchange.setApiKey() call or EXCHANGERATE_API_KEY environment variable is needed when using Frankfurter.

TypeScript Support

This library is written in TypeScript and provides full type definitions out of the box.

import { Money, Exchange, CurrencyCode, FrankfurterApi } from '@toneflix/money';

// CurrencyCode type ensures type safety

const currency: CurrencyCode = 'USD';

// Full IDE autocomplete and type checking

const money = new Money(100, currency);

const formatted: string = money.format();

// Async operations are properly typed

const result: number = await Exchange.from('USD').to('EUR').convert(100);

// Providers are selected by class

Exchange.setProvider(FrankfurterApi);

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

This project is licensed under the ISC License - see the LICENSE file for details.

Support

Credits

Created by Toneflix Technologies Limited

Exchange rates can be powered by ExchangeRate-API or Frankfurter, depending on the configured provider.

About

A simple and efficient money and currency conversion and formatting tool for JavaScript and TypeScript projects.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages