Skip to content

Commit

Permalink
[TypeScript] Add types to amount utils (#4207)
Browse files Browse the repository at this point in the history
* Add types to amount utils

* Release notes
  • Loading branch information
joel-jeremy authored Jan 21, 2025
1 parent 90dc050 commit 4850034
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -218,12 +218,12 @@ export function Transaction({
: {}),
}}
title={
inflow === null && outflow === null
outflow === null
? 'Invalid: unable to parse the value'
: amountToCurrency(outflow)
}
>
{amountToCurrency(outflow)}
{amountToCurrency(outflow || 0)}
</Field>
<Field
width={90}
Expand All @@ -235,12 +235,12 @@ export function Transaction({
: {}),
}}
title={
inflow === null && outflow === null
inflow === null
? 'Invalid: unable to parse the value'
: amountToCurrency(inflow)
}
>
{amountToCurrency(inflow)}
{amountToCurrency(inflow || 0)}
</Field>
</>
) : (
Expand Down Expand Up @@ -271,7 +271,7 @@ export function Transaction({
: amountToCurrency(amount)
}
>
{amountToCurrency(amount)}
{amountToCurrency(amount || 0)}
</Field>
</>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ import { renderCustomLabel } from './renderCustomLabel';
type PayloadItem = {
payload: {
date: string;
totalAssets: number | string;
totalDebts: number | string;
netAssets: number | string;
netDebts: number | string;
totalTotals: number | string;
totalAssets: number;
totalDebts: number;
netAssets: number;
netDebts: number;
totalTotals: number;
};
};

Expand Down Expand Up @@ -141,7 +141,9 @@ const customLabel = ({
((typeof props.value === 'number' ? props.value : 0) > 0 ? 10 : -10);
const textAnchor = props.index === 0 ? 'left' : 'middle';
const display =
props.value !== 0 ? `${amountToCurrencyNoDecimal(props.value)}` : '';
typeof props.value !== 'string' && props.value !== 0
? `${amountToCurrencyNoDecimal(props.value || 0)}`
: '';
const textSize = adjustTextSize({ sized: width, type: 'area' });

return renderCustomLabel(calcX, calcY, textAnchor, display, textSize);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,13 @@ type PayloadChild = {
type PayloadItem = {
payload: {
name: string;
totalAssets: number | string;
totalDebts: number | string;
netAssets: number | string;
netDebts: number | string;
totalTotals: number | string;
networth: number | string;
totalChange: number | string;
totalAssets: number;
totalDebts: number;
netAssets: number;
netDebts: number;
totalTotals: number;
networth: number;
totalChange: number;
children: [PayloadChild];
};
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ export function SpendingCard({
<PrivacyFilter activationFilters={[!isCardHovered]}>
{data &&
(difference && difference > 0 ? '+' : '') +
amountToCurrency(difference)}
amountToCurrency(difference || 0)}
</PrivacyFilter>
</Block>
</View>
Expand Down
55 changes: 37 additions & 18 deletions packages/loot-core/src/shared/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,21 @@ export function getNumberFormat({

// Number utilities

/**
* The exact amount.
*/
export type Amount = number;
/**
* The exact amount that is formatted based on the configured number format.
* For example, 123.45 would be '123.45' or '123,45'.
*/
export type CurrencyAmount = string;
/**
* The amount with the decimal point removed.
* For example, 123.45 would be 12345.
*/
export type IntegerAmount = number;

// We dont use `Number.MAX_SAFE_NUMBER` and such here because those
// numbers are so large that it's not safe to convert them to floats
// (i.e. N / 100). For example, `9007199254740987 / 100 ===
Expand All @@ -353,65 +368,69 @@ export function safeNumber(value: number) {
return value;
}

export function toRelaxedNumber(value: string) {
return integerToAmount(currencyToInteger(value) || 0);
export function toRelaxedNumber(currencyAmount: CurrencyAmount): Amount {
return integerToAmount(currencyToInteger(currencyAmount) || 0);
}

export function integerToCurrency(
n: number,
integerAmount: IntegerAmount,
formatter = getNumberFormat().formatter,
) {
return formatter.format(safeNumber(n) / 100);
return formatter.format(safeNumber(integerAmount) / 100);
}

export function amountToCurrency(n) {
return getNumberFormat().formatter.format(n);
export function amountToCurrency(amount: Amount): CurrencyAmount {
return getNumberFormat().formatter.format(amount);
}

export function amountToCurrencyNoDecimal(n) {
export function amountToCurrencyNoDecimal(amount: Amount): CurrencyAmount {
return getNumberFormat({
...numberFormatConfig,
hideFraction: true,
}).formatter.format(n);
}).formatter.format(amount);
}

export function currencyToAmount(str: string) {
export function currencyToAmount(
currencyAmount: CurrencyAmount,
): Amount | null {
let amount;
if (getNumberFormat().separatorRegex) {
amount = parseFloat(
str
currencyAmount
.replace(getNumberFormat().regex, '')
.replace(getNumberFormat().separatorRegex, '.'),
);
} else {
amount = parseFloat(
str
currencyAmount
.replace(getNumberFormat().regex, '')
.replace(getNumberFormat().separator, '.'),
);
}
return isNaN(amount) ? null : amount;
}

export function currencyToInteger(str: string) {
const amount = currencyToAmount(str);
export function currencyToInteger(
currencyAmount: CurrencyAmount,
): IntegerAmount | null {
const amount = currencyToAmount(currencyAmount);
return amount == null ? null : amountToInteger(amount);
}

export function stringToInteger(str: string) {
export function stringToInteger(str: string): number | null {
const amount = parseInt(str.replace(/[^-0-9.,]/g, ''));
if (!isNaN(amount)) {
return amount;
}
return null;
}

export function amountToInteger(n: number) {
return Math.round(n * 100);
export function amountToInteger(amount: Amount): IntegerAmount {
return Math.round(amount * 100);
}

export function integerToAmount(n) {
return parseFloat((safeNumber(n) / 100).toFixed(2));
export function integerToAmount(integerAmount: IntegerAmount): Amount {
return parseFloat((safeNumber(integerAmount) / 100).toFixed(2));
}

// This is used when the input format could be anything (from
Expand Down
6 changes: 6 additions & 0 deletions upcoming-release-notes/4207.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
category: Maintenance
authors: [joel-jeremy]
---

Add type to the the amount utils to clarify what's the difference between amount, integer amount, and currency.

0 comments on commit 4850034

Please sign in to comment.