Skip to content

A TypeScript/JavaScript library to make working with monetary values easier and safer.

License

Notifications You must be signed in to change notification settings

half0wl/money.ts

Repository files navigation

💵 money.ts

CI NPM Documentation

This library aims to make working with monetary values in TypeScript/JavaScript safer and easier.

Monetary values always have a currency. They are distinct by currency ($1 is not equivalent to €1), and each currency has different properties that affect how they're displayed, rounded, and parsed. It can be tricky to get all of this right, and if you're handling money at all, it can be expensive to get something wrong!

See: http://martinfowler.com/eaaCatalog/money.html

Installation

# Using npm:
$ npm i @half0wl/money

# Using yarn:
$ yarn add @half0wl/money

Import

// TypeScript
import { Money } from "@half0wl/money"

// JavaScript/CommonJS
'use strict';
const Money = require("@half0wl/money").Money

Features

  • Arithmetic (add, subtract, etc.) and comparison (equals, greater/less than, etc.)
  • Immutability. Every operation returns a new Money object, and properties are not modifiable
  • Locale-aware string formatting
  • Lightweight; zero external dependencies
  • JavaScript is fully supported. Enabling strict mode ('use strict';) is highly recommended, but this will work fine without it
  • Full documentation

Concept

A Money object has a currency and amount, where:

  • Currency is an ISO-4217 alpha code, e.g. USD, JPY, EUR, SGD
  • Amount is represented in the currency's lowest unit, e.g. US$5.00 = 500 cents = { currency: USD, amount: 500 }

Usage

Full API documentation for the Money class is available here.

import { Money } from "@half0wl/money"

/**
 * Basic operations
 */
const listing = new Money('USD', 19999)                // Default constructor from int
listing.getCurrency()                                  // => USD
listing.getAmount()                                    // => 19999
listing.toLocaleString()                               // => '$199.99'

const shipping = Money.fromFloat('USD', 15.00)         // From float
shipping.getAmount()                                   // => 1500
shipping.toLocaleString()                              // => '$15.00'

const xmasDiscount = Money.fromString('USD', '2000')   // From int-string
xmasDiscount.getAmount()                               // => 2000
xmasDiscount.toLocaleString()                          // => '$20.00'

const promoDiscount = Money.fromString('USD', '10.00') // From float-string
promoDiscount.getAmount()                              // => 1000
promoDiscount.toLocaleString()                         // => '$10.00'

const subtotal = listing
  .add(shipping)
  .subtract(xmasDiscount, promoDiscount)
subtotal.getCurrency()                                 // => 'USD'
subtotal.getAmount()                                   // => 18499
subtotal.toLocaleString()                              // => '$184.99'

/**
 * Other arithmetic operations
 */
subtotal.multiply(2.4).toLocaleString()                // => '$443.98'
subtotal.divide(8).toLocaleString()                    // => $23.12

/**
 * Comparisons
 */
promoDiscount.equals(promoDiscount)                    // => false
promoDiscount.greaterThan(promoDiscount)               // => true
shipping.greaterThanOrEqual(listing)                   // => false
shipping.lessThan(listing)                             // => true

/**
 * Formatting
 */
const tenDollars = new Money('USD', 1000)
// Using default locale (`en-US`):
tenDollars.toLocaleString()                            // => $10.00
// Using different locale:
tenDollars.toLocaleString('fr-CA')                     // => 10,00 $ US
// JSON
tenDollars.toJSON()                                    // => {
                                                       //      currency: 'USD',
                                                       //      amount: 1000
                                                       //    }

/**
 * Immutability
 */
// All operations return a new `Money` object:
const sixEur = new Money('EUR', 600)
const oneEur = new Money('EUR', 100)
sixEur.add(oneEur)       // This returns a new Money object!
sixEur.toLocaleString()  // => '€6.00'
                         // The amount value is *not* updated in-place.

// To get the result of `sixEur.add(oneEur)`:
const result = sixEur.add(oneEur)
result.toLocaleString()  // => '€7.00'

// Properties are *always* read-only:
// TypeScript
const twoEur = new Money('EUR', 200)
twoEur['amount'] = 0 // => error TS2540: Cannot assign to 'amount'
                     //    because it is a read-only property.

// JavaScript (in strict mode)
'use strict';
const threeEur = new Money('EUR', 300)
threeEur['amount'] = 0 // => TypeError: Cannot assign to read only
                       //    property 'amount' of object '#<Money>'

Development

Clone the repo and install dependencies:

$ git clone https://github.com/half0wl/money.ts.git
$ yarn install

Tests are located under /tests. To run them:

$ yarn test

Code documentation is written in and generated with TypeDoc. To generate docs:

$ yarn gen-docs

Acknowledgements

License

MIT

About

A TypeScript/JavaScript library to make working with monetary values easier and safer.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published