Modern TypeScript currency converter with type inference and multiple exchanges. Framework agnostic with clean architecture and minimal dependencies.
- 🚀 Modern TypeScript - Full type safety with intelligent inference
- 🔄 Multiple Exchanges - Google Finance, Fixer.io, and extensible architecture
- 🎯 Type Inference - Smart exchange and configuration type inference
- 🧩 Framework Agnostic - Works with any JavaScript/TypeScript project
- 📦 Minimal Dependencies - Only axios and cheerio for web scraping
- 🔧 Extensible - Easy to add custom exchanges
- 🌐 Clean APIs - Intuitive object-based and positional parameter APIs
- ⚡ High Performance - Optimized for speed and memory efficiency
npm install @mixxtor/currencyx-jsimport { createCurrency, exchanges } from '@mixxtor/currencyx-js'
// Create currency service with multiple exchanges
const currency = createCurrency({
default: 'google',
exchanges: {
google: exchanges.google({ base: 'USD' }),
fixer: exchanges.fixer({ accessKey: 'your-api-key' }),
},
})
// Convert currency
const result = await currency.convert({
amount: 100,
from: 'USD',
to: 'EUR',
})
if (result.success) {
console.log(`$100 USD = €${result.result} EUR`)
console.log(`Exchange rate: ${result.info.rate}`)
}Convert currency with explicit object parameters:
const result = await currency.convert({
amount: 100,
from: 'USD',
to: 'EUR',
})
// Result structure
interface ConversionResult {
success: boolean
query: { amount: number; from: string; to: string }
result?: number
info?: { rate: number; timestamp: number }
date: string
error?: { info: string; type?: string }
}Get exchange rates with object parameters:
const rates = await currency.getExchangeRates({
base: 'USD',
codes: ['EUR', 'GBP', 'JPY'],
})
// Result structure
interface ExchangeRatesResult {
success: boolean
base: string
rates: Record<string, number>
timestamp: number
date: string
error?: { info: string; type?: string }
}Shorthand for getting rates:
const rates = await currency.latestRates({ base: 'USD', codes: ['EUR', 'GBP'] })// Switch exchanges
currency.use('fixer')
// Get current exchange provider
const current = currency.getCurrentExchange() // 'fixer'
// List available exchanges
const exchanges = currency.getAvailableExchanges() // ['google', 'fixer']// Format currency (object parameters)
const formatted = currency.formatCurrency({ amount: 1234.56, code: 'USD', locale: 'en-US' })
// Result: "$1,234.56"
// Round values
const rounded = currency.round(123.456789, { precision: 2, direction: 'up' })
// Result: 123.46
// Get supported currencies
const currencies = await currency.getSupportedCurrencies()
// Result: ['USD', 'EUR', 'GBP', 'JPY', ...]
// Get current exchange provider
const currentProvider = currency.getCurrentExchange()
// Result: 'google' | 'fixer' | etc.
// Get all available exchanges
const exchanges = currency.getAvailableExchanges()
// Result: ['google', 'fixer']
// Currency information utilities
const allCurrencies = currency.getList()
// Get all available currency information
const usdInfo = currency.getByCode('USD')
// Get currency info by ISO code
const dollarCurrencies = currency.getBySymbol('$')
// Get currency info by symbol
const usCurrency = currency.getByCountry('US')
// Get currency by country code
const euroCurrencies = currency.filterByName('Euro')
// Filter currencies by name
const usCurrencies = currency.filterByCountry('US')
// Filter currencies by country
// Round money according to currency rules
const rounded = currency.roundMoney(123.456, 'USD')
// Automatically rounds according to USD rounding rulesFree provider, no API key required:
const currency = createCurrency({
default: 'google',
exchanges: {
google: exchanges.google({
base: 'USD', // Base currency (default: 'USD')
timeout: 5000, // Request timeout in ms (optional)
}),
},
})Requires API key from fixer.io:
const currency = createCurrency({
default: 'fixer',
exchanges: {
fixer: exchanges.fixer({
accessKey: 'your-api-key', // Required: Your Fixer.io API key
base: 'USD', // Base currency (default: 'USD' for this library, Fixer default: 'EUR')
timeout: 10000, // Request timeout in ms (optional)
}),
},
})Configure multiple exchanges and switch between them:
const currency = createCurrency({
default: 'google',
exchanges: {
google: exchanges.google({ base: 'USD' }),
fixer: exchanges.fixer({ accessKey: 'your-key' }),
},
})
// Use Google Finance
currency.use('google')
const googleResult = await currency.convert({ amount: 100, from: 'USD', to: 'EUR' })
// Switch to Fixer.io
currency.use('fixer')
const fixerResult = await currency.convert({ amount: 100, from: 'USD', to: 'EUR' })Full TypeScript support with intelligent type inference:
// Exchange names are type-safe
const currency = createCurrency({
default: 'google', // ✅ Type-safe
exchanges: {
google: exchanges.google({ base: 'USD' }),
fixer: exchanges.fixer({ accessKey: 'key' }),
},
})
// Only valid exchange names are allowed
currency.use('google') // ✅ Valid
currency.use('invalid') // ❌ TypeScript errorAll methods return result objects with success indicators:
const result = await currency.convert({
amount: 100,
from: 'USD',
to: 'EUR',
})
if (result.success) {
console.log(`Converted: ${result.result}`)
console.log(`Rate: ${result.info.rate}`)
console.log(`Timestamp: ${result.info.timestamp}`)
} else {
console.error(`Error: ${result.error?.info}`)
console.error(`Type: ${result.error?.type}`)
}Extend the system with custom exchanges:
import { BaseCurrencyExchange } from '@mixxtor/currencyx-js'
import type { ConvertParams, ExchangeRatesParams } from '@mixxtor/currencyx-js'
class CustomExchange extends BaseCurrencyExchange {
readonly name = 'custom'
constructor(config: { base: string; apiKey?: string }) {
super()
this.base = config.base || 'USD'
// Initialize with your config
}
async convert(params: ConvertParams) {
try {
// Your custom conversion logic
const rate = await this.getConvertRate(params.from, params.to)
const result = params.amount * rate
return this.createConversionResult(params.amount, params.from, params.to, result, rate)
} catch (error) {
return this.createConversionResult(params.amount, params.from, params.to, undefined, undefined, {
info: error.message,
type: 'custom_error',
})
}
}
async latestRates(params: ExchangeRatesParams) {
try {
// Your custom rates logic
const rates = await this.fetchRatesFromAPI(params)
return this.createExchangeRatesResult(params.base, rates)
} catch (error) {
return this.createExchangeRatesResult(params.base, {}, { info: error.message, type: 'custom_error' })
}
}
async getConvertRate(from: string, to: string): Promise<number> {
// Implement your rate fetching logic
return 0.85 // Example rate
}
private async fetchRatesFromAPI(params: { base: string; codes?: string[] }) {
// Implement your API call logic
return { EUR: 0.85, GBP: 0.73 }
}
}
// Use your custom exchange
const currency = createCurrency({
default: 'custom',
exchanges: {
custom: new CustomExchange({ base: 'USD', apiKey: 'your-key' }),
},
})Check the examples directory for more usage patterns:
- Selective API Demo - Demonstrates the API design principles
The API has been simplified and modernized:
// Old API (v0.x)
const currency = new CurrencyService()
currency.addProvider('google', new GoogleProvider())
const result = await currency.convert(100, 'USD', 'EUR')
// New API (v1.x)
const currency = createCurrency({
default: 'google',
exchanges: {
google: exchanges.google({ base: 'USD' }),
},
})
const result = await currency.convert({ amount: 100, from: 'USD', to: 'EUR' })- Node.js >= 18.0.0
- TypeScript >= 4.5.0 (for TypeScript projects)
- axios - For HTTP requests to currency APIs
- cheerio - For HTML parsing (Google Finance web scraping)
Contributions are welcome! Please read CONTRIBUTING.md for guidelines.
MIT License - see LICENSE file for details.
See CHANGELOG.md for version history and changes.