Dinero.js
Dinero.js version

# Using different amount types

Dinero expects amounts as `number` by default. In most cases, this is more than enough, but there are times when you might hit the limitations of the biggest and smallest numbers you can safely represent.

A typical use case is when you need to represent colossal amounts of money. Take the world debt, which reached \$258 trillion in 2020. In JavaScript, the biggest number you can accurately represent is 9007199254740991 (9 quadrillions and some spare change). Still, since Dinero requires you to pass amounts in minor currency units, you actually "lose" two orders of magnitude, and can only represent around \$90 trillion.

``````import { dinero } from 'dinero.js';
import { USD } from '@dinero.js/currencies';

// Don't do this!
// 25800000000000000 is too big for accurate representation
// in IEEE 754 numbers.
const price = dinero({ amount: 25800000000000000, currency: USD });
``````

Another example is when you need to represent cryptocurrencies, which typically have high exponents. In 2021, the Ether can be subdivided down to 18 fraction digits, meaning you can't even represent 1 ETH with the `number` type.

``````import { dinero } from 'dinero.js';

const ETH = {
code: 'ETH',
base: 10,
exponent: 18,
};

// Don't do this!
// 1000000000000000000 is too big for accurate representation
// in IEEE 754 numbers.
const price = dinero({ amount: 1000000000000000000, currency: ETH });
``````

In such cases, you need to rely on safer alternatives, such as the bigint primitive or third-parties like big.js.

## Copy linkUsing Dinero with bigint

Dinero provides a `bigint` calculator for you to use out of the box. You can create your own `dinero` function by passing the calculator to the `createDinero` factory.

``````import { calculator } from '@dinero.js/calculator-bigint';
import { createDinero } from 'dinero.js';

const dineroBigint = createDinero({ calculator });
``````

You can then use this function to create Dinero objects and manipulate them with any Dinero function. Keep in mind that once you're in `bigint` land, every numeric value you pass needs to be a `bigint` as well.

``````import { add } from 'dinero.js';

const USD = {
code: 'USD',
base: 10n,
exponent: 2n,
};

const d1 = dineroBigint({ amount: 500n, currency: USD });
const d2 = dineroBigint({ amount: 100n, currency: USD });

add(d1, d2); // a Dinero object with amount `600n`
``````

## Copy linkUsing Dinero with a custom amount type

Dinero.js delegates all calculations to a type-specific calculator object. The calculator fully determines what amount type you can pass to Dinero objects. Therefore, by changing the calculator with one of a different type, you can create Dinero objects of this type.

You can implement your own if you want to use a third-party library.

### Copy linkImplementing a custom calculator

Dinero.js delegates all calculations to a type-specific calculator object. You can implement a custom calculator for a given type and pass it to Dinero to use the library with amounts of this type.

A calculator implements the `Calculator` interface. For example, here's what it can look like with big.js.

``````import Big from 'big.js';
import { Calculator, ComparisonOperator } from 'dinero.js';

const calculator: Calculator<Big> = {
compare: (a, b) => a.cmp(b) as unknown as ComparisonOperator,
decrement: (v) => v.minus(new Big(1)),
increment: (v) => v.plus(new Big(1)),
integerDivide: (a, b) => a.div(b).round(0, Big.roundDown),
modulo: (a, b) => a.mod(b),
multiply: (a, b) => a.times(b),
power: (a, b) => a.pow(Number(b)),
subtract: (a, b) => a.minus(b),
toNumber: (v) => v.toNumber(),
zero: () => new Big(0),
};
``````

Once you have your calculator, you can build a custom `dinero` function.

``````import { createDinero } from 'dinero.js';

// ...

const bigDinero = createDinero({ calculator });
``````

You might notice that you're passing the full calculator, meaning you're shipping calculator methods you might not use. This is unlikely to represent a bottleneck, especially if you're using Dinero with a third-party library like big.js because you're only referencing methods that already exist on every `Big` object you create.

## Copy linkPicking the right amount type

Depending on what you use Dinero.js for, you might want to choose a different amount type better suited to your needs. Knowing what to pick depends on your constraints, use case, and what compromises you can to make.

With amount types, the main trade-off is between precision and performance. Safe arbitrary precision comes at the cost of speed, so you need to properly assess your needs before deciding.

### Copy linkWhen to use number

By default, Dinero.js uses the `number` type. It's ideal when you need to express monetary values that will never exceed what the type can safely represent.

The `number` primitive type lets you create double-precision floats (or "doubles") using the IEEE 754 standard. It works well for many use cases and provides excellent performance. However, doubles can only represent a limited range of numbers (from `-(2^53 - 1)` to `2^53 - 1`). Anything below or above gets truncated when converted to binary and stored in memory, resulting in imprecisions.

Using Dinero.js with `number`s works well when you know and control the numbers to represent. It works for many use cases including dynamic pricing pages, ecommerce sites, or money management applications, as long as you're confident you'll never exceed the type limitations.

• Limited range of numbers that can be accurately represented

### Copy linkWhen to use bigint

Dinero.js provides a `bigint` calculator, allowing you to use the library with native `bigint`s. It's ideal when you need to represent monetary values with large amounts, beyond what the `number` type safely supports.

The `bigint` primitive type lets you create arbitrarily large integers and ensures arithmetic precision. However, `bigint`s are much slower than `number`s, and not available in all environments. They're also impossible to polyfill and hard to transpile without incurring significant performance costs.

Using Dinero.js with the `bigint` type is recommended when you need to use numbers that exceed the `number` limitations. It can also act as a safeguard when you don't control the monetary amounts in your app, and you have reasons to believe you might exceed the limits. This applies to use cases such as cryptocurrency or stock trading applications.

• Arbitrary-precision integer support
• Faster than any userland arbitrary-precision library (see Chrome benchmark)

### Copy linkWhen to use libraries

If you need to support arbitrarily large integers in browsers that don't support `bigint`s, you can write a custom calculator to use Dinero.js with libraries like big.js or JSBI.

Contrary to the `bigint` type which relies on operators, libraries expose APIs to safely manipulate arbitrarily large integers. Such solutions usually rely on `string`s or arrays of `number`s, making them more widely supported across browsers. However, this has a significant impact on performance because of the extra runtime logic, algorithmic complexity, and increase in bundle size.

Using Dinero.js with arbitrary precision arithmetic libraries makes sense when you wish you could use `bigint`s but cannot because you need to support environments that don't implement them.

• Better browser and Node.js support than `bigint`s, transpilable and polyfillable
• Significantly slower than `number`s and `bigint`s