@tevari/helpers
Version:
Collection of various small helpers for javascript and typescript based projects
317 lines (288 loc) • 9.78 kB
text/typescript
import { Function1 } from "./functions";
import { Order } from "./misc";
import { DOT, SPACE, stringValueOrEmpty } from "./strings";
/**
* Calculates the average of all numbers given in the array.
*
* @param numbers The numbers to be averaged.
* @param rounded whether the result average should be rounded.
* @returns the average result.
*/
export const numberAverage = (numbers: number[], rounded = false): number => {
if (numbers.length === 0) return 0;
const total = numbers.filter((v) => v !== null).reduce((total, current) => total + current, 0);
const average = total / numbers.length;
const finalAverage = rounded ? Math.round(average) : average;
return finalAverage >= 0 ? finalAverage : 0;
};
/**
* Gets a number comparator function in the given order.
*
* @param order The order of the result.
* @returns a comparator function in the given order.
*/
export const numberGetComparator =
(order: Order = "desc") =>
(a: number, b: number) => {
if (order === "asc") return a - b;
return b - a;
};
/**
* Gets a number comparator function in the given order from the values extracted using the given supplier function.
*
* @param order The order of the result.
* @returns a comparator function in the given order.
*/
export const numberGetValueComparator =
<T>(order: Order = "desc", extractor: Function1<T, number>) =>
(a: T, b: T): number => {
const numberA = extractor(a);
const numberB = extractor(b);
if (order === "asc") return numberA - numberB;
return numberB - numberA;
};
/**
* An ascendent number comparator.
*/
export const NUMBER_COMPARATOR_ASC = numberGetComparator("asc");
/**
* An descendent number comparator.
*/
export const NUMBER_COMPARATOR_DESC = numberGetComparator("desc");
/**
* An ascendent number comparator from extracted values.
*/
export const NUMBER_VALUE_COMPARATOR_ASC = <T>(extractor: Function1<T, number>) =>
numberGetValueComparator("asc", extractor);
/**
* An descendent number comparator from extracted values.
*/
export const NUMBER_VALUE_COMPARATOR_DESC = <T>(extractor: Function1<T, number>) =>
numberGetValueComparator("desc", extractor);
/**
* Returns a random number contained between the given mion and max values inclusively.
*
* @param min The min value.
* @param max The max value.
* @returns the result random number.
*/
export const numberRandom = (min: number, max: number): number => {
return Math.random() * (max - min) + min;
};
/**
* Number seperator accepted types.
*/
export type NumberSeparator = "." | ",";
/**
* Number thousand seperator accepted types.
*/
export type NumberThousandSeparator = " " | ",";
/**
* Number formatters options.
*/
export interface INumberFormatOptions {
/**
* The desired number of decimals to be displayed.
*/
nbOfDecimals?: number;
/**
* The desired float number separator.
*/
separator?: NumberSeparator;
/**
* The desired thousand number separator.
*/
thousandSeparator?: NumberThousandSeparator;
/**
* Minimun number of digit to display on the integer side (before the decimals).
*/
minDigits?: number;
/**
* Whether the sign should alwaws be displayed ("+42%").
* Default: false
*/
forceDisplaySign?: boolean;
}
/**
* Number percentage formatter options.
*/
export interface INumberFormatPercentageOptions {
/**
* Whether you want the formating to display negative values.
* If `false`, negative values will be displayed as 0%.
* Default: false
*/
withNegativeValues?: boolean;
}
/**
* Formats the given number into a percentage string representation.
*
* @param percentage The number to format.
* @param options The formatter options.
* @returns a percentage string representation of the given number.
*/
export const numberFormatPercentage = (
percentage: number,
options?: INumberFormatOptions & INumberFormatPercentageOptions,
) => {
const { nbOfDecimals = 1, withNegativeValues = false, forceDisplaySign = false } = options ?? {};
const fixedPercentage = Number(percentage.toFixed(nbOfDecimals));
if (Number.isNaN(fixedPercentage)) return "0%";
if (!withNegativeValues && fixedPercentage <= 0) return "0%";
if (fixedPercentage >= 100) return `${stringValueOrEmpty(forceDisplaySign && "+")}100%`;
if (Number.isInteger(fixedPercentage)) return `${numberFormatInteger(Math.round(percentage), options)}%`;
return `${numberFormatFloatWithDecimals(fixedPercentage, options)}%`;
};
/**
* Formats the given number into a float string representation with forced decimal.
*
* @param percentage The number to format.
* @param options The formatter options.
* @returns a float string representation of the given number.
*/
export const numberFormatFloatWithDecimals = (float?: number, options?: INumberFormatOptions) => {
const { separator = DOT, nbOfDecimals = 1 } = options ?? {};
if (!float || Number.isNaN(float)) return `0${separator}0`;
return numberFormatLarge(float, { ...options, nbOfDecimals });
};
/**
* Formats the given number into a float string representation. No decimal will be displayed of not needed.
*
* @param percentage The number to format.
* @param options The formatter options.
* @returns either a float or integer string representation of the given number.
*/
export const numberFormatFloat = (float?: number, options?: INumberFormatOptions): string => {
const { nbOfDecimals = 1 } = options ?? {};
if (!float || Number.isNaN(float)) return "0";
const fixed = Number(float.toFixed(nbOfDecimals));
if (Number.isNaN(fixed)) return "0";
if (Number.isInteger(fixed)) return `${numberFormatInteger(float, options)}`;
return `${numberFormatLarge(fixed, { ...options, nbOfDecimals })}`;
};
/**
* Formats the given number into a integer string representation.
*
* @param percentage The number to format.
* @param options The formatter options.
* @returns either a float or integer string representation of the given number.
*/
export const numberFormatInteger = (integer: number, options?: INumberFormatOptions): string => {
const { minDigits = 1, forceDisplaySign = false } = options ?? {};
const rounded = Math.round(integer);
if (minDigits > 1) {
return `${stringValueOrEmpty(forceDisplaySign && rounded > 0 && "+")}${String(rounded).padStart(minDigits, "0")}`;
}
return `${numberFormatLarge(rounded, options)}`;
};
/**
* Formats the given number into a string representation handling thousand separators.
*
* @param value The number to format.
* @param options The formatter options.
* @returns the string representation of the given number.
*/
export const numberFormatLarge = (value: number, options?: INumberFormatOptions) => {
const {
nbOfDecimals = Number.isInteger(value) ? 0 : 1,
separator = DOT,
thousandSeparator = SPACE,
forceDisplaySign = false,
} = options ?? {};
return `${stringValueOrEmpty(forceDisplaySign && value > 0 && "+")}${value
.toFixed(nbOfDecimals)
.replace(/\B(?<!\.\d*)(?=(\d{3})+(?!\d))/g, thousandSeparator)
.replace(DOT, separator)}`;
};
export const NumberHelpers = {
/**
* Calculates the average of all numbers given in the array.
*
* @param numbers The numbers to be averaged.
* @param rounded whether the result average should be rounded.
* @returns the average result.
*/
average: numberAverage,
/**
* Returns a random number contained between the given mion and max values inclusively.
*
* @param min The min value.
* @param max The max value.
* @returns the result random number.
*/
random: numberRandom,
};
export const NumberComparators = {
/**
* An ascendent number comparator.
*/
asc: NUMBER_COMPARATOR_ASC,
/**
* An descendent number comparator.
*/
desc: NUMBER_COMPARATOR_DESC,
/**
* An ascendent number comparator from extracted values.
*/
valueAsc: NUMBER_VALUE_COMPARATOR_ASC,
/**
* An descendent number comparator from extracted values.
*/
valueDesc: NUMBER_VALUE_COMPARATOR_DESC,
};
export const NumberFormatters = {
/**
* Formats the given number into a percentage string representation.
*
* @param percentage The number to format.
* @param options The formatter options.
* @returns a percentage string representation of the given number.
*/
percentage: numberFormatPercentage,
/**
* Formats the given number into a float string representation with forced decimal.
*
* @param percentage The number to format.
* @param options The formatter options.
* @returns a float string representation of the given number.
*/
floatWithDecimal: numberFormatFloatWithDecimals,
/**
* Formats the given number into a float string representation. No decimal will be displayed of not needed.
*
* @param percentage The number to format.
* @param options The formatter options.
* @returns either a float or integer string representation of the given number.
*/
float: numberFormatFloat,
/**
* Formats the given number into a integer string representation.
*
* @param percentage The number to format.
* @param options The formatter options.
* @returns either a float or integer string representation of the given number.
*/
integer: numberFormatInteger,
/**
* Formats the given number into a string representation handling thousand separators.
*
* @param value The number to format.
* @param options The formatter options.
* @returns the string representation of the given number.
*/
large: numberFormatLarge,
};
export const Numbers = {
/**
* Number helper methods.
*/
helper: NumberHelpers,
/**
* Number comparators.
*/
comparator: NumberComparators,
/**
* Number formatters.
*/
formatter: NumberFormatters,
};