Ecommerce with JS
Not quite. It works for many numbers, but there are some edge cases.
Your function:
export function round2(value: number | string) {
if (typeof value === 'number') {
return Math.round((value + Number.EPSILON) * 100) / 100;
} else if (typeof value === 'string') {
return Math.round((Number(value) + Number.EPSILON) * 100) / 100;
} else {
throw new Error('Value is not a number or string');
}
}
What it does well
round2(1.234); // 1.23
round2(1.235); // 1.24
round2("12.345"); // 12.35
The Number.EPSILON trick helps with some floating-point issues:
Math.round(1.005 * 100) / 100
// 1
round2(1.005)
// 1.01
What it doesn't guarantee
Invalid strings
round2("abc")
// NaN
No error is thrown because "abc" is still a string.
You may want:
const num = Number(value);
if (Number.isNaN(num)) {
throw new Error("Invalid number");
}
Very large numbers
Floating-point precision limits still apply:
round2(123456789012345.6789)
JavaScript numbers are IEEE-754 doubles, so some precision is already lost before rounding.
Doesn't always return exactly 2 decimal places
round2(1)
// 1
round2(1.2)
// 1.2
It rounds to 2 decimal places, but doesn't display 2 decimal places.
If you want:
1.00
1.20
use:
value.toFixed(2)
which returns a string.
Cleaner version
export function round2(value: number | string): number {
const num = Number(value);
if (Number.isNaN(num)) {
throw new Error('Invalid number');
}
return Math.round((num + Number.EPSILON) * 100) / 100;
}
This handles both numbers and numeric strings with less duplication.
One more subtle point: even the Number.EPSILON technique is not perfect for every decimal value because some numbers cannot be represented exactly in binary floating point. For financial calculations requiring exact decimal rounding, libraries such as decimal.js are usually a better choice than native JavaScript numbers.
Comments
Post a Comment