monie-utils
v1.1.1
Published
A comprehensive TypeScript library for money-related utilities including currency formatting, conversion, validation, and financial calculations
Maintainers
Readme
💰 Monie Utils
A comprehensive TypeScript library for money-related utilities including currency formatting, conversion, validation, and financial calculations.
✨ Features
- 🎯 Type-safe - Built with TypeScript for excellent developer experience
- 🌍 International - Support for multiple currencies and locales
- 💱 Currency operations - Formatting, conversion, and validation
- 🧮 Financial calculations - Interest, loans, investments, and more
- 📊 Business utilities - Payment processing, subscriptions, analytics
- 🚀 Lightweight - Tree-shakeable with zero dependencies
- ✅ Well-tested - Comprehensive test coverage
- 📚 Well-documented - Extensive documentation and examples
🚀 Installation
npm install monie-utilsyarn add monie-utilspnpm add monie-utils📖 Quick Start
import {
isValidAmount,
isValidCurrency,
} from 'monie-utils';
// Validate amounts
console.log(isValidAmount(100.50)); // true
console.log(isValidAmount(NaN)); // false
// Validate currencies
console.log(isValidCurrency('USD')); // true
console.log(isValidCurrency('BTC')); // true
console.log(isValidCurrency('INVALID')); // false
📚 API Reference
Currency Formatting
formatCurrency(amount: number, currency: string, options?: FormatCurrencyOptions): FormattedCurrency
Formats a currency amount with locale-specific formatting.
formatCurrency(1234.56, 'USD')
// Returns: { formatted: '$1,234.56', amount: 1234.56, currency: 'USD', locale: 'en-US', isCompact: false }
formatCurrency(1234.56, 'EUR', { locale: 'de-DE', showCode: true })
// Returns: { formatted: '1.234,56 EUR', amount: 1234.56, currency: 'EUR', locale: 'de-DE', isCompact: false }formatMoney(amount: number, currency: string, locale?: string): string
Simple string formatting for currency amounts.
formatMoney(1234.56, 'USD')
// Returns: '$1,234.56'
formatMoney(1234.56, 'EUR', 'de-DE')
// Returns: '1.234,56 €'formatCents(cents: number, currency: string, options?: FormatCurrencyOptions): FormattedCurrency
Formats amounts from smallest currency unit (cents/satoshis).
formatCents(12345, 'USD')
// Returns: { formatted: '$123.45', amount: 123.45, currency: 'USD', locale: 'en-US', isCompact: false }
formatCents(10000000, 'BTC')
// Returns: { formatted: '₿0.10000000', amount: 0.1, currency: 'BTC', locale: 'en-US', isCompact: false }formatCompactCurrency(amount: number, currency: string, options?: FormatCurrencyOptions): FormattedCurrency
Formats large amounts in compact notation (1M, 1B, etc.).
formatCompactCurrency(1500000, 'USD')
// Returns: { formatted: '$1.5M', amount: 1500000, currency: 'USD', locale: 'en-US', isCompact: true }
formatCompactCurrency(2500000000, 'USD')
// Returns: { formatted: '$2.5B', amount: 2500000000, currency: 'USD', locale: 'en-US', isCompact: true }Percentage Formatting
formatPercentage(decimal: number, options?: PercentageOptions): string
Formats decimal values as percentages.
formatPercentage(0.1525)
// Returns: '15.25%'
formatPercentage(0.1525, { precision: 1, locale: 'de-DE' })
// Returns: '15,3 %'Localization
formatCurrencyByLocale(amount: number, currency: string, locale: string): string
Formats currency with specific locale rules.
formatCurrencyByLocale(1234.56, 'USD', 'en-US')
// Returns: '$1,234.56'
formatCurrencyByLocale(1234.56, 'EUR', 'de-DE')
// Returns: '1.234,56 €'getLocaleCurrencyInfo(locale: string): LocaleCurrencyInfo
Gets currency information for a locale.
getLocaleCurrencyInfo('en-US')
// Returns: { currency: 'USD', symbol: '$', name: 'US Dollar' }
getLocaleCurrencyInfo('de-DE')
// Returns: { currency: 'EUR', symbol: '€', name: 'Euro' }formatWithGrouping(amount: number, locale?: string): string
Adds thousand separators based on locale.
formatWithGrouping(1234567.89)
// Returns: '1,234,567.89'
formatWithGrouping(1234567.89, 'de-DE')
// Returns: '1.234.567,89'formatDecimalPlaces(amount: number, decimalPlaces: number): string
Formats number with specific decimal places.
formatDecimalPlaces(123.456789, 2)
// Returns: '123.46'
formatDecimalPlaces(123.1, 4)
// Returns: '123.1000'Validation and Parsing
isValidAmount(amount: unknown): amount is number
Checks if a value is a valid money amount.
isValidAmount(100.50)
// Returns: true
isValidAmount(NaN)
// Returns: falseisValidCurrency(currencyCode): currencyCode is string
Validates currency codes against ISO 4217 and cryptocurrencies.
isValidCurrency('USD')
// Returns: true
isValidCurrency('BTC')
// Returns: true
isValidCurrency('INVALID')
// Returns: falseisPositiveAmount(amount: number): boolean
Checks if an amount is positive.
isPositiveAmount(100)
// Returns: true
isPositiveAmount(-50)
// Returns: falseisWithinRange(amount: number, min: number, max: number): boolean
Checks if an amount is within a specified range.
isWithinRange(50, 10, 100)
// Returns: true
isWithinRange(150, 10, 100)
// Returns: falseparseAmount(amountString: string): ParsedAmount
Parses string to number amount.
parseAmount('123.45')
// Returns: { amount: 123.45, isValid: true }
parseAmount('invalid')
// Returns: { amount: 0, isValid: false }parseCurrencyString(currencyString: string): ParsedCurrency
Extracts amount and currency from formatted string.
parseCurrencyString('$123.45')
// Returns: { amount: 123.45, currency: 'USD', isValid: true }
parseCurrencyString('€1.234,56')
// Returns: { amount: 1234.56, currency: 'EUR', isValid: true }normalizeAmount(amount: number, decimalPlaces?: number): number
Normalizes amount to standard format.
normalizeAmount(123.456789)
// Returns: 123.46
normalizeAmount(123.456789, 4)
// Returns: 123.4568parseFormattedCurrency(formattedString: string, locale?: string): ParsedCurrency
Parses formatted currency string with locale awareness.
parseFormattedCurrency('$1,234.56', 'en-US')
// Returns: { amount: 1234.56, currency: 'USD', isValid: true }
parseFormattedCurrency('1.234,56 €', 'de-DE')
// Returns: { amount: 1234.56, currency: 'EUR', isValid: true }Currency Conversion
convertCurrency(amount: number, fromCurrency: string, toCurrency: string, rate?: number): ConversionResult
Converts between currencies with exchange rates.
convertCurrency(100, 'USD', 'EUR', 0.85)
// Returns: { amount: 85, fromCurrency: 'USD', toCurrency: 'EUR', rate: 0.85 }
convertCurrency(100, 'USD', 'USD')
// Returns: { amount: 100, fromCurrency: 'USD', toCurrency: 'USD', rate: 1 }convertWithFee(amount: number, rate: number, feePercentage: number): ConversionWithFee
Converts currency with transaction fee.
convertWithFee(100, 0.85, 2.5)
// Returns: { convertedAmount: 85, fee: 2.125, totalCost: 87.125, effectiveRate: 0.8713 }bulkConvert(amounts: number[], fromCurrency: string, toCurrency: string, rate: number): BulkConversionResult
Converts multiple amounts at once.
bulkConvert([100, 200, 300], 'USD', 'EUR', 0.85)
// Returns: { convertedAmounts: [85, 170, 255], totalOriginal: 600, totalConverted: 510, rate: 0.85 }Arithmetic Operations
roundMoney(amount: number, precision?: number): number
Rounds money to specified precision.
roundMoney(123.456)
// Returns: 123.46
roundMoney(123.456, 1)
// Returns: 123.5addMoney(amount1: number, amount2: number, currency?: string): number
Adds two money amounts.
addMoney(100.25, 50.75)
// Returns: 151
addMoney(100.25, 50.75, 'USD')
// Returns: 151subtractMoney(amount1: number, amount2: number, currency?: string): number
Subtracts money amounts.
subtractMoney(100.75, 25.25)
// Returns: 75.5
subtractMoney(100.75, 25.25, 'USD')
// Returns: 75.5multiplyMoney(amount: number, multiplier: number): number
Multiplies money by a number.
multiplyMoney(50.25, 3)
// Returns: 150.75
multiplyMoney(100, 1.5)
// Returns: 150divideMoney(amount: number, divisor: number): number
Divides money by a number.
divideMoney(150, 3)
// Returns: 50
divideMoney(100, 4)
// Returns: 25calculateTip(amount: number, percentage: number): number
Calculates tip amount.
calculateTip(100, 15)
// Returns: 15
calculateTip(85.50, 20)
// Returns: 17.1calculateTax(amount: number, taxRate: number): number
Calculates tax amount.
calculateTax(100, 8.5)
// Returns: 8.5
calculateTax(250, 10)
// Returns: 25calculateDiscount(amount: number, discountRate: number): number
Calculates discount amount.
calculateDiscount(100, 10)
// Returns: 10
calculateDiscount(250, 15)
// Returns: 37.5calculateSimpleInterest(principal: number, rate: number, time: number): number
Calculates simple interest.
calculateSimpleInterest(1000, 5, 2)
// Returns: 100
calculateSimpleInterest(5000, 3.5, 1.5)
// Returns: 262.5calculateCompoundInterest(principal: number, rate: number, time: number, frequency?: number): CompoundInterestResult
Calculates compound interest.
calculateCompoundInterest(1000, 5, 2)
// Returns: { finalAmount: 1102.5, interestEarned: 102.5, effectiveRate: 5.125 }
calculateCompoundInterest(1000, 5, 2, 12)
// Returns: { finalAmount: 1104.89, interestEarned: 104.89, effectiveRate: 5.244 }splitAmount(totalAmount: number, numberOfParts: number): number[]
Splits amount into equal parts.
splitAmount(100, 3)
// Returns: [33.33, 33.33, 33.34]
splitAmount(150, 4)
// Returns: [37.5, 37.5, 37.5, 37.5]distributeProportionally(totalAmount: number, ratios: number[]): number[]
Distributes amount by ratios.
distributeProportionally(100, [1, 2, 3])
// Returns: [16.67, 33.33, 50]
distributeProportionally(500, [40, 30, 30])
// Returns: [200, 150, 150]calculatePercentageOfTotal(amount: number, total: number): number
Calculates percentage share.
calculatePercentageOfTotal(25, 100)
// Returns: 25
calculatePercentageOfTotal(150, 500)
// Returns: 30Loan and Credit Utilities
calculateMonthlyPayment(principal: number, rate: number, termMonths: number): number
Calculates monthly loan payment.
calculateMonthlyPayment(200000, 4.5, 360)
// Returns: 1013.37
calculateMonthlyPayment(50000, 6, 60)
// Returns: 966.64calculateLoanBalance(principal: number, rate: number, termMonths: number, paymentsMade: number): number
Calculates remaining loan balance.
calculateLoanBalance(200000, 4.5, 360, 12)
// Returns: 197834.23
calculateLoanBalance(50000, 6, 60, 24)
// Returns: 28844.35calculateTotalInterest(principal: number, rate: number, termMonths: number): number
Calculates total interest over loan term.
calculateTotalInterest(200000, 4.5, 360)
// Returns: 164813.42
calculateTotalInterest(50000, 6, 60)
// Returns: 7998.12generateAmortizationSchedule(principal: number, rate: number, termMonths: number): AmortizationEntry[]
Generates complete amortization schedule.
generateAmortizationSchedule(100000, 5, 12)
// Returns: [
// { month: 1, payment: 8560.75, principal: 8144.08, interest: 416.67, balance: 91855.92 },
// { month: 2, payment: 8560.75, principal: 8178.02, interest: 382.73, balance: 83677.90 },
// ...
// ]calculateCreditUtilization(usedCredit: number, totalCredit: number): number
Calculates credit utilization ratio.
calculateCreditUtilization(2500, 10000)
// Returns: 25
calculateCreditUtilization(1200, 5000)
// Returns: 24calculateMinimumPayment(balance: number, rate: number, minimumRate: number): number
Calculates minimum credit payment.
calculateMinimumPayment(5000, 18, 2)
// Returns: 100
calculateMinimumPayment(2500, 24, 3)
// Returns: 75calculatePayoffTime(balance: number, payment: number, rate: number): PayoffResult
Calculates time to pay off debt.
calculatePayoffTime(5000, 200, 18)
// Returns: { months: 30, totalInterest: 983.45, totalPaid: 5983.45 }
calculatePayoffTime(10000, 300, 24)
// Returns: { months: 43, totalInterest: 2804.32, totalPaid: 12804.32 }Investment and Returns
calculateROI(initialInvestment: number, finalValue: number): number
Calculates return on investment.
calculateROI(10000, 12000)
// Returns: 20
calculateROI(5000, 4500)
// Returns: -10calculateAnnualizedReturn(initialValue: number, finalValue: number, years: number): number
Calculates annualized return.
calculateAnnualizedReturn(10000, 15000, 3)
// Returns: 14.47
calculateAnnualizedReturn(5000, 7500, 2)
// Returns: 22.47calculateDividendYield(dividendPerShare: number, pricePerShare: number): number
Calculates dividend yield.
calculateDividendYield(2.50, 50)
// Returns: 5
calculateDividendYield(1.25, 75)
// Returns: 1.67calculateFutureValue(presentValue: number, rate: number, periods: number): number
Calculates future value.
calculateFutureValue(10000, 7, 10)
// Returns: 19671.51
calculateFutureValue(5000, 5, 20)
// Returns: 13266.49Subscription and Recurring Payments
calculateSubscriptionValue(monthlyAmount: number, months: number): number
Calculates total subscription cost.
calculateSubscriptionValue(29.99, 12)
// Returns: 359.88
calculateSubscriptionValue(99, 6)
// Returns: 594compareSubscriptionPlans(plans: SubscriptionPlan[]): PlanComparison[]
Compares subscription plans.
compareSubscriptionPlans([
{ name: 'Basic', monthlyPrice: 10, features: [] },
{ name: 'Pro', monthlyPrice: 25, features: [] }
])
// Returns: [
// { plan: 'Basic', monthlyPrice: 10, annualPrice: 120, savings: 0 },
// { plan: 'Pro', monthlyPrice: 25, annualPrice: 300, savings: 0 }
// ]calculateProrationAmount(amount: number, daysUsed: number, totalDays: number): number
Calculates prorated amount.
calculateProrationAmount(100, 15, 30)
// Returns: 50
calculateProrationAmount(299, 10, 31)
// Returns: 96.45calculateUpgradeCredit(oldPlan: SubscriptionPlan, newPlan: SubscriptionPlan, daysRemaining: number): UpgradeCredit
Calculates upgrade credit.
calculateUpgradeCredit(
{ name: 'Basic', monthlyPrice: 10 },
{ name: 'Pro', monthlyPrice: 25 },
15
)
// Returns: { credit: 5, additionalCost: 12.5, totalCost: 7.5 }calculateAnnualEquivalent(amount: number, frequency: 'monthly' | 'weekly' | 'quarterly'): number
Converts to annual amount.
calculateAnnualEquivalent(100, 'monthly')
// Returns: 1200
calculateAnnualEquivalent(25, 'weekly')
// Returns: 1300calculateNextPaymentDate(startDate: Date, frequency: 'monthly' | 'weekly' | 'quarterly'): Date
Calculates next payment date.
calculateNextPaymentDate(new Date('2024-01-15'), 'monthly')
// Returns: Date object for 2024-02-15
calculateNextPaymentDate(new Date('2024-01-15'), 'weekly')
// Returns: Date object for 2024-01-22calculateTotalRecurringCost(amount: number, frequency: 'monthly' | 'weekly' | 'quarterly', duration: number): number
Calculates total recurring cost.
calculateTotalRecurringCost(50, 'monthly', 12)
// Returns: 600
calculateTotalRecurringCost(25, 'weekly', 52)
// Returns: 1300Utility Functions
roundToNearestCent(amount: number): number
Rounds to nearest cent.
roundToNearestCent(123.456)
// Returns: 123.46
roundToNearestCent(99.994)
// Returns: 99.99roundToBankersRounding(amount: number, decimalPlaces?: number): number
Applies banker's rounding (round half to even).
roundToBankersRounding(2.125, 2)
// Returns: 2.12
roundToBankersRounding(2.135, 2)
// Returns: 2.14truncateToDecimalPlaces(amount: number, places: number): number
Truncates without rounding.
truncateToDecimalPlaces(123.789, 2)
// Returns: 123.78
truncateToDecimalPlaces(99.999, 1)
// Returns: 99.9ceilToNearestCent(amount: number): number
Ceils to nearest cent.
ceilToNearestCent(123.451)
// Returns: 123.46
ceilToNearestCent(99.001)
// Returns: 99.01formatThousands(number: number, options?: ThousandsOptions): string
Adds thousand separators.
formatThousands(1234567.89)
// Returns: '1,234,567.89'
formatThousands(1234567.89, { thousandsSeparator: '.', decimalSeparator: ',' })
// Returns: '1.234.567,89'formatToHundreds(amount: number, options?: ThousandsOptions): string
Formats cents to dollars with separators.
formatToHundreds(123456)
// Returns: '1,234.56'
formatToHundreds(987654, { thousandsSeparator: ' ', decimalSeparator: ',' })
// Returns: '9 876,54'removeFormattingFromNumber(formattedString: string): string
Removes formatting characters.
removeFormattingFromNumber('$1,234.56')
// Returns: '1234.56'
removeFormattingFromNumber('€ 1.234,56')
// Returns: '1234.56'convertToWords(amount: number, options?: { currency?: string }): NumberToWordsResult
Converts number to words.
convertToWords(123.45)
// Returns: { words: 'one hundred twenty-three and forty-five cents' }
convertToWords(1500, { currency: 'USD' })
// Returns: { words: 'one thousand five hundred dollars', currency: 'USD' }formatAccountNumber(accountNumber: string, options?: AccountNumberOptions): FormattedAccountResult
Formats account numbers with masking.
formatAccountNumber('1234567890')
// Returns: { formatted: '******7890', masked: true, groupSize: 4 }
formatAccountNumber('1234567890', { maskCharacter: 'X', showLast: 6 })
// Returns: { formatted: 'XXXX567890', masked: true, groupSize: 4 }🧪 Development
Prerequisites
- Node.js 18+
- npm, yarn, or pnpm
Setup
# Clone the repository
git clone https://github.com/spiderocious/monie-utils.git
cd monie-utils
# Install dependencies
npm install
# Run tests
npm test
# Run tests in watch mode
npm run test:watch
# Build the library
npm run build
# Lint and format
npm run lint
npm run formatScripts
npm run dev- Start development server with Vitenpm run build- Build the library with tsupnpm test- Run tests with Jestnpm run test:watch- Run tests in watch modenpm run test:coverage- Run tests with coverage reportnpm run lint- Lint code with ESLintnpm run lint:fix- Fix linting issuesnpm run format- Format code with Prettiernpm run type-check- Run TypeScript type checking
🙏 Acknowledgments
- Inspired by financial libraries from Stripe, PayStack, Monnify, and other payment processors
- Built with modern TypeScript and development tools
- Thanks to all contributors and the open-source community
Made with ❤️ by Oluwaferanmi (https://github.com/spiderocious)
