Hi everyone! Today I'm excited to announce easymoney: opensource library for operating with monetary values in JavaScript and Typescript.
We publish the first stable release v1.0.0. In this post, we try to explain some sort of motivation and briefly describe what is ready today and what to expect from our future plans and roadmap.
About the library
easymoney is a library for operating with monetary values in JavaScript and Typescript. It's an implementation of a pattern Martin Fowler's Money Type fromΒ "Patterns of Enterprise Application Architecture".
It's an old and widely used pattern that is implemented in many other languages e.g.:
Highlights
First-class Typescript support
Support all standard math operations
Custom currencies support
Support big number values
Support crypto
Support formatting
Principles that we put in our library
As small as possible bundle size
Nearly 100 per cent coverage, proofing reliability
Clear communications and transparency within the community
In-depth
First-class Typescript support
The library is written in Typescript. We really like Typescript and try to achieve flexibility between reliability and simplicity in its usage.
Support all standard math operations
Addition
import { createMoney } from '@easymoney/money';
const money1 = createMoney({ amount: 100, currency: 'USD' });
const money2 = createMoney({ amount: 106, currency: 'USD' });
const money3 = money1.add(money2).getAmount();
// => 206
Multiplication
import { createMoney } from '@easymoney/money';
const money1 = createMoney({ amount: 100, currency: 'USD' });
const money2 = createMoney({ amount: 2, currency: 'USD' });
const money3 = money1.multiply(money2).getAmount();
// => 200
Supports all standard math operations. Subtraction, multiplication, division, and so on.
Custom currencies support
import { createCurrencyList } from "@easymoney/currencies";
const currencies = [{ minorUnit: 2, code: "XBT" },
{ minorUnit: 5, code: "DXBT" }];
const list = createCurrencyList(currencies);
list.contains("USD")
// => false
list.contains("XBT")
// => true
Depending on the application, the user may want the list of currencies used by the application to contain other fields, such as the view field to display the symbol (e.g., βΏ), or may want to operate with other currencies that are not on the ISO list at all (e.g., various cryptocurrencies). For this reason, we thought it's important to give users the flexibility to customize, if they wish, how they will present currencies in their application.
Support big number values
We also support numbers bigger than Number.MAX_SAFE_INTEGER
Support custom and crypto currencies
import { createMoneyCryptoFormatter } from "@easymoney/crypto-formatter";
import { createMoney } from "@easymoney/money";
const BTC = { code: "BTC", minorUnit: 8 };
const money = createMoney({ amount: 6, currency: BTC });
money.getCurrency();
// => { code: "BTC", minorUnit: 8 }
const formattedValue = createMoneyCryptoFormatter().format(money);
// 0.00000005BTC
We understand that the use of cryptocurrencies is on the rise, so we consider it necessary to give our users who work in this area a convenient API for their daily tasks. Now, out of the box we support only LTC, ETH, BTC, but we can expand this list in future releases.
Support formatting
Formatting ISO currencies with Intl.NumberFormat
import { createMoneyIntlFormatter } from "@easymoney/formatter"
import { createMoney } from '@easymoney/money';
const money = createMoney({ amount: 5, currency: "USD" });
const money1 = createMoney({ amount: 50, currency: "USD" });
const formatted = createMoneyIntlFormatter().format(money);
// => "$0.05"
const formatted1 = createMoneyIntlFormatter()
.format(money,
"en-US",
{minimumFractionDigits: 1, maximumFractionDigits: 1});
// => "$0.5"
Formatting cryptocurrencies
import { createMoneyCryptoFormatter } from "@easymoney/crypto-formatter"
import { createMoney } from '@easymoney/money';
import { cryptoCurrenciesMap } from "@easymoney/currencies"
const money = createMoney({ amount: 5, currency: "LTC" });
const formatted = createMoneyCryptoFormatter().format(money);
// => "0.00000005LTC"
const money1 = createMoney({ amount: 50, currency: cryptoCurrenciesMap.ETH });
const formatted1 = createMoneyCryptoFormatter().format(money);
// => "0.000000000000000005ETH"
const money = { amount: 5, currency: "ETH" };
const formattedValue = createFormatter().format(createMoney(money), {
currencyPosition: -1
});
// => ETH0.000000000000000005
Modular api
Our library is divided into different packages. For example:
@easymoney/crypto-formatter ββ crypto currency formatting;
@easymoney/formatter ββ formatting ISO currencies using Intl.NumberFormat;
@easymoney/money ββ work with monetary values with numbers that fit into Number.MAX_SAFE_INTEGER;
@easymoney/bignumber.js ββ works with monetary values of any range, integrated with the library bignumber.js;
@easymoney/currencies ββ works with any range of values integrated with bignumber.js library.
We tried to build the architecture so that the functionality of the library was available as much as possible by domain. This allows for maximum flexibility in the construction of third-party modules (about this below), as well as to have the smallest possible final bundle size so that you need only download the part of the functions that you require.
Reliability
We believe that good software is a reliable software. Therefore, in addition to types, there should be testing behind the guarantee of reliability. With this in mind, we pay a great deal of attention to testing. Most of the code is covered by unit tests, but we also use prop-based testing and a fast-check tool to brush up on possible unrecorded branches that are not always visible with conventional unit tests. We think that modern javascript has all the tools needed to ensure the reliability of the software being developed.
Also, we use codecov, to make sure the coverage doesn't decrease between releases.
Transparency
It's an opensource product, so the community must stay in the first place. So keeping this in mind, we want this product to be transparent with the community, so everyone can get quick feedback or find what they need. That's why we are going to pay a lot of attention to the documentation and to the quickest possible resolution of user problems.
For this we have taken the following steps:
- We have an open roadmap, where you can track the process of future features that you can suggest in issues.
- We try to explain all motivations in starting guides and a future series of articles will describe all possible functionality and problems. The first one is already written.
- We will keep detailed releases so you can always track changes in the library.
- We are going to use templates for issues so that you can find similar problems in the issue tracker without much effort.
We realize that there is still a lot of work ahead of us on documentation and on adding the necessary functionality for users. Now we are actively working on documentation and adding guides on how to use our library. In parallel, we will try to implement new features as far as possible. If you want to help, you always can ask to help on my Twitter and I will try to find some work for you and say thank you very much for your help.
Get Started
Thank you
Thanks for reading the post and for your time. Big thanks to people who helped me to finish this project, especially Jan Janucewicz, who helped with integrating bignumber.js and made a great effort to tests and documentation.
If you find bugs, please report them on our Github issues. Alternatively, you can always ask me on Twitter.
Feel free to ask questions, to express any opinion, and discuss this from your point of view. Make code, not war. β€οΈ
Top comments (1)
So exciting! Congrats on your launch Andrey π Also, great introduction. Seems like a useful library!