ts-data-forge
Version:
[](https://www.npmjs.com/package/ts-data-forge) [](https://www.npmjs.com/package/ts-data-forge) [ • 12.7 kB
JavaScript
/**
* Namespace providing utility functions for number manipulation and validation.
*
* This namespace offers a comprehensive set of type-safe number utilities
* including:
*
* - Type conversion and validation
* - Type guards for numeric constraints (non-zero, non-negative, positive)
* - Range checking and clamping operations
* - Mathematical operations with type safety
* - Rounding utilities
*
* Many functions in this namespace leverage TypeScript's type system to provide
* compile-time guarantees about numeric constraints.
*/
var Num;
(function (Num) {
/**
* Converts an unknown value to a number. Alias for the `Number` constructor.
*
* @example
*
* ```ts
* const input = '123.45';
*
* const result = Num.from(input);
*
* assert.isTrue(result === 123.45);
* ```
*
* @param n The value to convert.
* @returns The numeric representation of `n`.
*/
Num.from = Number;
/**
* Type guard that checks if a number is non-zero.
*
* When this function returns `true`, TypeScript narrows the type to exclude
* zero, providing compile-time safety for division operations and other
* calculations that require non-zero values.
*
* @example
*
* ```ts
* const value: number = 5;
*
* if (Num.isNonZero(value)) {
* // Safe to divide now that we know value is non-zero
* // eslint-disable-next-line total-functions/no-partial-division
* const inverted = 1 / value;
*
* assert.isTrue(inverted === 0.2);
* }
*
* assert.isFalse(Num.isNonZero(0));
* ```
*
* @template N - The numeric literal type or number type to check
* @param num - The number to check
* @returns `true` if the number is not zero, `false` otherwise
*/
Num.isNonZero = (num) => num !== 0;
/**
* Type guard that checks if a number is non-negative (greater than or equal
* to zero).
*
* When this function returns `true`, TypeScript narrows the type to exclude
* negative values, which is useful for operations that require non-negative
* inputs like array indices or measurements.
*
* @example
*
* ```ts
* const candidate = 10;
*
* if (Num.isNonNegative(candidate)) {
* const index: number = candidate;
*
* assert.isTrue(index === 10);
* }
*
* assert.isFalse(Num.isNonNegative(-1));
* ```
*
* @template N - The numeric literal type or number type to check
* @param num - The number to check
* @returns `true` if the number is >= 0, `false` otherwise
*/
Num.isNonNegative = (num) => num >= 0;
/**
* Type guard that checks if a number is positive (greater than zero).
*
* When this function returns `true`, TypeScript narrows the type to exclude
* zero and negative values. This is particularly useful for validating inputs
* that must be strictly positive, such as dimensions, counts, or rates.
*
* @example
*
* ```ts
* const amount = 42;
*
* if (Num.isPositive(amount)) {
* assert.isTrue(amount > 0);
* }
*
* assert.isFalse(Num.isPositive(0));
* ```
*
* @template N - The numeric literal type or number type to check
* @param num - The number to check
* @returns `true` if the number is > 0, `false` otherwise
*/
Num.isPositive = (num) => num > 0;
/**
* Creates a function that checks if a number `x` is within the range
* `lowerBound <= x < upperBound`.
*
* @example
*
* ```ts
* const isGrade = Num.isInRange(0, 100);
*
* assert.isTrue(isGrade(50));
*
* assert.isFalse(isGrade(100));
* ```
*
* @param lowerBound The lower bound (inclusive).
* @param upperBound The upper bound (exclusive).
* @returns A function that takes a number `x` and returns `true` if `x` is in
* the range, `false` otherwise.
*/
Num.isInRange = (lowerBound, upperBound) => (x) => lowerBound <= x && x < upperBound;
/**
* Creates a function that checks if a number `x` is within the range
* `lowerBound <= x <= upperBound`.
*
* @example
*
* ```ts
* const isPercentage = Num.isInRangeInclusive(0, 100);
*
* assert.isTrue(isPercentage(100));
*
* assert.isFalse(isPercentage(-1));
* ```
*
* @param lowerBound The lower bound (inclusive).
* @param upperBound The upper bound (inclusive).
* @returns A function that takes a number `x` and returns `true` if `x` is in
* the range, `false` otherwise.
*/
Num.isInRangeInclusive = (lowerBound, upperBound) => (x) => lowerBound <= x && x <= upperBound;
/**
* Creates a type guard that checks if a number is an unsigned integer within
* a specified range.
*
* This function returns a predicate that validates whether a number is:
*
* - A safe integer (no floating point)
* - Within the range [lowerBound, upperBound)
*
* The returned type guard provides precise type narrowing when the bounds are
* SmallUint literals, making it ideal for array index validation.
*
* @example
*
* ```ts
* const indexGuard = Num.isUintInRange(0, 5);
*
* assert.isTrue(indexGuard(3));
*
* assert.isFalse(indexGuard(5));
*
* assert.isFalse(indexGuard(-1));
* ```
*
* @template L - The lower bound as a SmallUint literal type
* @template U - The upper bound as a SmallUint literal type
* @param lowerBound - The minimum value (inclusive)
* @param upperBound - The maximum value (exclusive)
* @returns A type guard function that validates and narrows number types
*/
Num.isUintInRange = (lowerBound, upperBound) => (x) => Number.isSafeInteger(x) && lowerBound <= x && x < upperBound;
/**
* Creates a type guard that checks if a number is an unsigned integer within
* a specified inclusive range.
*
* This function returns a predicate that validates whether a number is:
*
* - A safe integer (no floating point)
* - Within the range [lowerBound, upperBound] (both bounds inclusive)
*
* The returned type guard provides precise type narrowing when the bounds are
* SmallUint literals, useful for validating scores, percentages, or other
* bounded values.
*
* @example
*
* ```ts
* const inclusiveGuard = Num.isUintInRangeInclusive(0, 5);
*
* assert.isTrue(inclusiveGuard(5));
*
* assert.isFalse(inclusiveGuard(6));
* ```
*
* @template L - The lower bound as a SmallUint literal type
* @template U - The upper bound as a SmallUint literal type
* @param lowerBound - The minimum value (inclusive)
* @param upperBound - The maximum value (inclusive)
* @returns A type guard function that validates and narrows number types
*/
Num.isUintInRangeInclusive = (lowerBound, upperBound) => (x) => Number.isSafeInteger(x) && lowerBound <= x && x <= upperBound;
function clamp(...args) {
switch (args.length) {
case 3: {
const [target, lowerBound, upperBound] = args;
return !Number.isFinite(target)
? lowerBound
: Math.max(lowerBound, Math.min(upperBound, target));
}
case 2: {
const [lowerBound, upperBound] = args;
return (target) => clamp(target, lowerBound, upperBound);
}
}
}
Num.clamp = clamp;
/**
* Performs type-safe division with compile-time zero-check.
*
* This function leverages TypeScript's type system to prevent division by
* zero at compile time. The divisor must be typed as NonZeroNumber or a
* non-zero numeric literal.
*
* @param a - The dividend
* @param b - The divisor (must be non-zero, enforced by types)
* @returns The quotient of a / b
*/
Num.div = (a, b) =>
// eslint-disable-next-line total-functions/no-partial-division
a / b;
/**
* Performs integer division using floor division.
*
* Computes `⌊a / b⌋` by flooring both operands before division and then
* flooring the result. This ensures integer arithmetic semantics.
*
* Note: Unlike `div`, this function does not enforce non-zero divisor at
* compile time. Division by zero returns `NaN`.
*
* @param a - The dividend
* @param b - The divisor
* @returns The integer quotient, or `NaN` if b is zero
*/
Num.divInt = (a, b) =>
// eslint-disable-next-line total-functions/no-partial-division
Math.floor(Math.floor(a) / Math.floor(b));
/**
* Rounds a number to a specified number of decimal places.
*
* Uses the standard rounding algorithm (round half up) to round the number to
* the given precision. The precision must be a positive safe integer.
*
* @param num - The number to round
* @param precision - The number of decimal places (must be positive)
* @returns The rounded number
*/
Num.roundAt = (num, precision) => {
const digit = 10 ** precision;
// eslint-disable-next-line total-functions/no-partial-division
return Math.round(num * digit) / digit;
};
/**
* Rounds a number to the nearest integer using bitwise operations.
*
* This function uses a bitwise OR trick for potentially faster rounding.
* Note: This implementation rounds half up for positive numbers but may
* behave differently for negative numbers compared to Math.round.
*
* @param num - The number to round
* @returns The rounded integer as an Int branded type
*/
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
Num.roundToInt = (num) => Math.trunc(num + 0.5);
/**
* Creates a reusable rounding function with a fixed precision.
*
* This is a curried version of roundAt that returns a function configured to
* always round to the specified number of decimal places. Useful for creating
* consistent rounding behavior across multiple values.
*
* @param digit - The number of decimal places for rounding
* @returns A function that rounds numbers to the specified precision
*/
Num.round = (digit) => {
const powAmount = 10 ** digit;
return (target) =>
// eslint-disable-next-line total-functions/no-partial-division
Num.roundToInt(powAmount * target) / powAmount;
};
/**
* Converts NaN values to undefined while preserving all other numbers.
*
* This function is useful for handling potentially invalid numeric operations
* in a type-safe way, converting NaN results to undefined for easier handling
* with optional chaining or nullish coalescing.
*
* @template N - The numeric type (literal or number)
* @param num - The number to check
* @returns The original number if not NaN, otherwise undefined
*/
Num.mapNaN2Undefined = (num) => Number.isNaN(num)
? undefined
: // eslint-disable-next-line total-functions/no-unsafe-type-assertion
num;
/**
* Type-safe increment operation for SmallUint values.
*
* Increments a SmallUint (0-40) by 1 with the result type computed at compile
* time. This provides type-level arithmetic for small unsigned integers,
* useful for type-safe counter operations.
*
* @template N - A SmallUint literal type (0-40)
* @param n - The SmallUint value to increment
* @returns The incremented value with type Increment<N>
*/
Num.increment = (n) =>
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
(n + 1);
/**
* Type-safe decrement operation for positive SmallInt values.
*
* Decrements a positive SmallInt (1-40) by 1 with the result type computed at
* compile time. This provides type-level arithmetic for small positive
* integers, useful for type-safe countdown operations.
*
* @template N - A positive SmallInt literal type (1-40)
* @param n - The positive SmallInt value to decrement
* @returns The decremented value with type Decrement<N>
*/
Num.decrement = (n) =>
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
(n - 1);
})(Num || (Num = {}));
export { Num };
//# sourceMappingURL=num.mjs.map