sendou.ink/app/utils/number.ts
Kalle 5a2fcf7a9f
Some checks are pending
Tests and checks on push / run-checks-and-tests (push) Waiting to run
Updates translation progress / update-translation-progress-issue (push) Waiting to run
Add tests and documentation to number utils
Also improved safeNumberParse robustness
2025-07-06 22:00:54 +03:00

79 lines
2.2 KiB
TypeScript

import * as R from "remeda";
/**
* Rounds a number to a specified number of decimal places.
*
* @example
* ```typescript
* roundToNDecimalPlaces(3.14159); // returns 3.14
* roundToNDecimalPlaces(3.14159, 3); // returns 3.142
* roundToNDecimalPlaces(2.5, 0); // returns 3
* ```
*/
export function roundToNDecimalPlaces(num: number, n = 2) {
return Number((Math.round(num * 10 ** n) / 10 ** n).toFixed(n));
}
/**
* Truncates a number to a specified number of decimal places without rounding.
*
* @example
* ```typescript
* cutToNDecimalPlaces(3.9999, 2); // returns 3.99
* cutToNDecimalPlaces(3.12, 1); // returns 3.1
* cutToNDecimalPlaces(100, 2); // returns 100
* cutToNDecimalPlaces(3.0001, 2); // returns 3
* ```
*/
export function cutToNDecimalPlaces(num: number, n = 2) {
const multiplier = 10 ** n;
const truncatedNum = Math.trunc(num * multiplier) / multiplier;
const result = truncatedNum.toFixed(n);
return Number(n > 0 ? result.replace(/\.?0+$/, "") : result);
}
/**
* Calculates the average (arithmetic mean) of an array of numbers.
* Returns 0 if the array is empty.
*
* @example
* ```typescript
* averageArray([2, 4, 6, 8]); // returns 5
* averageArray([-2, -4, -6, -8]); // returns -5
* averageArray([10, -10, 20, -20]); // returns 0
* averageArray([42]); // returns 42
* averageArray([]); // returns 0
* ```
*/
export function averageArray(arr: number[]) {
if (arr.length === 0) return 0;
return R.sum(arr) / arr.length;
}
/**
* Safely parses a string into a number, returning `null` if the input is `null`,
* empty, or not a valid number.
*
* Trims whitespace from the input before parsing. If the trimmed string is empty
* or cannot be converted to a valid number, returns `null`.
*
* @example
* ```typescript
* safeNumberParse("42"); // returns 42
* safeNumberParse(" 3.14 "); // returns 3.14
* safeNumberParse(""); // returns null
* safeNumberParse("abc"); // returns null
* safeNumberParse(null); // returns null
* ```
*/
export function safeNumberParse(value: string | null) {
if (value === null) return null;
const trimmed = value.trim();
if (trimmed === "") return null;
const result = Number(trimmed);
return Number.isNaN(result) ? null : result;
}