Introduction

Working with currency can always be a challenge. To problem lies within the floating numbers (.0212). Typescript like many other programming languages struggle to calculate with those, resulting often in wrong results. Thats why I should never use float numbers in the database and instead, always use only integers. In this article I’m gonna cover how to fix this problem.


The big.js API

The big.js api targets just this very problem float numbers. It enables me to access a variety of functions, that help me get the numbers right.

I can install it via:

npm install big.js
npm install @types/big.js --save-dev

I also linked the official documentation here:

Source
πŸ“„ big.js website

big.ts

If I want to customize the big.js api according to my needs, I can do so with creating this file:

src/lib/big.ts

Here I can define how my numbers should be, for example:

  • It should have 2 decimal places
  • Round to nearest, if ties, then round to even numbers (1.65 β†’ 1.6)
import Big from "big.js";
 
Big.DP = 2;
Big.RM = Big.roundHalfEven;
 
export const MyBig = Big;

currency.ts

The currency.ts defines my functions I’m gonna need within my application and makes them accessible for all files. It is placed here:

src/utils/currency.ts

Some example functions could be:

  • Take a Dollar number, turn it into Cents (4,35 β†’ 435)
  • Take a Cent number, turn it into Dollars (657 β†’ 6.57)
  • Turn a Cent number into a Currency number (320 β†’ $3.20)
import { MyBig } from "@/lib/big";
 
export const toCent = (amount: number) =>
  new MyBig(amount).mul(100).round(2).toNumber();
 
export const fromCent = (amount: number) =>
  new MyBig(amount).div(100).round(2).toNumber();
 
export const toCurrencyFromCent = (amount: number) =>
  new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "USD",
  }).format(fromCent(amount));

Note: The currency.ts makes use of the big.ts file


currency function usage

This chapter will showcase some possible use cases.

upsertTicket

In the database there should always only be integers and never floats. Therefore I need to transform the Dollar number (3.25) into a Cent number (325), before storing it in the database.

 
// uptaded zod schema
const upsertTicketSchema = z.object({
  // ...
  bounty: z.coerce.number().positive(),
});
 
 
export const upsertTicket = async ( ... ) => {
  try {
    const data = upsertTicketSchema.parse({
      // ...
      bounty: formData.get("bounty"),
    });
 
	// parse bounty into cents
    const dbData = {
      ...data,
      bounty: toCent(data.bounty),
    };
	
	// before pushing to the database
    await prisma.ticket.upsert({
      where: { id: id || "" },
      update: dbData,
      create: dbData,
    });
  } 
};

Input as dollars only

Since the currency is stored in cents (integers) in the database, I will need to convert it back do dollars:

<Input
	id="bounty"
	name="bounty"
	type="number"
	step=".01"
	defaultValue={
		ticket?.bounty ? fromCent(ticket?.bounty) : ""
	}
/>

Paragraph as dollar with currency $

If I also want to display the currency icon, I need to use this function:

// 499 -> $4.99
<p>{toCurrencyFromCent(ticket.bounty)}</p>

Conclusion

Working with floats isn’t easy but thankfully there are people that create incredible APIs for the community, so we have less headache and don’t have to fix it on our own.