UNPKG

ts-data-forge

Version:

[![npm version](https://img.shields.io/npm/v/ts-data-forge.svg)](https://www.npmjs.com/package/ts-data-forge) [![npm downloads](https://img.shields.io/npm/dm/ts-data-forge.svg)](https://www.npmjs.com/package/ts-data-forge) [![License](https://img.shields.

289 lines 13.3 kB
/** @internal */ export declare namespace TsDataForgeInternals { /** * Internal utilities for creating and managing refined (branded) number * types. * * This namespace provides factory functions and type utilities for building * type-safe numeric operations with compile-time constraints. It serves as * the foundation for all branded number types in the library, including: * * - Integer types (Int, SafeInt, Int8, Int16, Int32) * - Unsigned types (UInt, UInt8, UInt16, UInt32) * - Constrained types (NonZero, NonNegative, Positive) * - Range-bounded types * * The utilities handle: * * - Type validation and narrowing * - Arithmetic operations that preserve type constraints * - Automatic clamping for bounded types * - Random number generation within type bounds * * @internal This namespace is not part of the public API */ namespace RefinedNumberUtils { type UnknownNumberBrand = ChangeBaseBrand<UnknownBrand, number>; /** * Converts a branded number type to include the Int brand. * * @template N - A branded number type * @internal */ export type ToInt<N extends UnknownNumberBrand> = IntersectBrand<N, Int>; type ToNonZero<N extends UnknownNumberBrand> = IntersectBrand<N, NonZeroNumber>; type ToNonZeroIntWithSmallInt<N extends Int> = WithSmallInt<CastToInt<ToNonZero<N>>>; /** * Converts a branded number type to include the NonNegativeNumber brand. * * @template N - A branded number type * @internal */ export type ToNonNegative<N extends UnknownNumberBrand> = IntersectBrand<N, NonNegativeNumber>; /** * Removes the non-zero brand constraint from a branded number type. Used * when operations may produce zero values. * * @template N - A branded number type * @internal */ export type RemoveNonZeroBrandKey<N extends UnknownNumberBrand> = Brand<GetBrandValuePart<N>, RelaxedExclude<UnwrapBrandTrueKeys<N>, '!=0'> & string, UnwrapBrandFalseKeys<N> & string>; type CastToInt<N> = N extends Int ? N : never; /** * Generates a type-safe API for a branded number type based on its * characteristics. * * This type dynamically constructs an object type with appropriate methods * based on the number class. For example: * * - Integer types don't get floor/ceil/round methods * - Non-negative types don't get abs method * - Range-bounded types get MIN_VALUE/MAX_VALUE constants * * @template N - The branded number type * @template classes - Union of characteristics: 'int' | 'non-negative' | * 'positive' | 'range' * @internal */ export type NumberClass<N extends UnknownNumberBrand, classes extends 'int' | 'non-negative' | 'positive' | 'range'> = ('int' extends classes ? unknown : 'positive' extends classes ? Readonly<{ floor: (x: N, y: N) => RemoveNonZeroBrandKey<ToInt<N>>; ceil: (x: N, y: N) => ToInt<N>; round: (x: N, y: N) => RemoveNonZeroBrandKey<ToInt<N>>; }> : Readonly<{ floor: (x: N, y: N) => ToInt<N>; ceil: (x: N, y: N) => ToInt<N>; round: (x: N, y: N) => ToInt<N>; }>) & ('non-negative' extends classes ? Readonly<{ MIN_VALUE: number; clamp: (a: number) => N; }> : unknown) & ('non-negative' extends classes ? unknown : 'positive' extends classes ? unknown : Readonly<{ abs: (x: N) => ToNonNegative<N>; }>) & ('positive' extends classes ? Readonly<{ MIN_VALUE: number; clamp: (a: number) => N; }> : unknown) & ('range' extends classes ? Readonly<{ MIN_VALUE: number; MAX_VALUE: number; clamp: (a: number) => N; }> : unknown) & Readonly<{ is: (a: number) => a is N; min: (...values: readonly N[]) => N; max: (...values: readonly N[]) => N; random: (min: N, max: N) => N; pow: (x: N, y: N) => N; add: (x: N, y: N) => N; sub: (x: N, y: N) => N; mul: (x: N, y: N) => N; div: (x: N, y: ToNonZero<N>) => N; }>; type OperatorsForInteger<ElementType extends Int, MIN_VALUE extends number, MAX_VALUE extends number, ElementTypeWithSmallInt extends WithSmallInt<ElementType> = WithSmallInt<ElementType>> = Readonly<{ MIN_VALUE: MIN_VALUE; MAX_VALUE: MAX_VALUE; is: (a: number) => a is ElementType; abs: (x: ElementTypeWithSmallInt) => ToNonNegative<ElementType>; min: (...values: readonly ElementTypeWithSmallInt[]) => ElementType; max: (...values: readonly ElementTypeWithSmallInt[]) => ElementType; pow: (x: ElementTypeWithSmallInt, y: ElementTypeWithSmallInt) => ElementType; add: (x: ElementTypeWithSmallInt, y: ElementTypeWithSmallInt) => ElementType; sub: (x: ElementTypeWithSmallInt, y: ElementTypeWithSmallInt) => ElementType; mul: (x: ElementTypeWithSmallInt, y: ElementTypeWithSmallInt) => ElementType; div: (x: ElementTypeWithSmallInt, y: ToNonZeroIntWithSmallInt<ElementType>) => ElementType; random: (min?: ElementTypeWithSmallInt, max?: ElementTypeWithSmallInt) => ElementType; randomNonZero: (min?: ElementTypeWithSmallInt, max?: ElementTypeWithSmallInt) => ElementType; castType: <N extends number>(x: N) => ElementType & N; clamp: TypeEq<MAX_VALUE | MIN_VALUE, undefined> extends true ? undefined : (x: number) => ElementType; }>; /** * Factory function that creates a complete set of type-safe operations for * integer types. * * This function generates: * * - Type guards and validators * - Arithmetic operations that preserve type constraints * - Utility functions (min, max, abs, random) * - Automatic clamping for bounded types * * All operations ensure results remain within the type's constraints, using * clamping when bounds are specified. * * @example * * ```ts * const intOps = TsDataForgeInternals.RefinedNumberUtils.operatorsForInteger< * SafeInt, * number, * number * >({ * integerOrSafeInteger: 'SafeInteger', * MIN_VALUE: Number.MIN_SAFE_INTEGER, * MAX_VALUE: Number.MAX_SAFE_INTEGER, * typeNameInMessage: 'SafeInt', * } as const); * * const six = intOps.castType(6); * * const four = intOps.castType(4); * * const sum = intOps.add(six, four); * * const difference = intOps.sub(six, four); * * const product = intOps.mul(six, four); * * const quotient = intOps.div(six, intOps.castType(2)); * * const roundedClamp = intOps.clamp(1.5); * * const randomValue = intOps.random(); * * assert.isTrue(sum === 10); * * assert.isTrue(difference === 2); * * assert.isTrue(product === 24); * * assert.isTrue(quotient === 3); * * assert.isTrue(roundedClamp === 2); * * assert.isTrue(Number.isSafeInteger(randomValue)); * ``` * * @template ElementType - The integer branded type * @template MIN_VALUE - Optional minimum value for bounded types * @template MAX_VALUE - Optional maximum value for bounded types * @param config - Configuration object * @param config.integerOrSafeInteger - Whether to use Number.isInteger or * Number.isSafeInteger * @param config.nonZero - If true, excludes zero from valid values * @param config.MIN_VALUE - Minimum valid value (inclusive) * @param config.MAX_VALUE - Maximum valid value (inclusive) * @param config.typeNameInMessage - Human-readable type name for error * messages * @returns Object containing all type-safe operations for the integer type * @internal */ export const operatorsForInteger: <ElementType extends Int, MIN_VALUE extends number, MAX_VALUE extends number>({ integerOrSafeInteger, nonZero, MIN_VALUE, MAX_VALUE, typeNameInMessage, }: Readonly<{ integerOrSafeInteger: "Integer" | "SafeInteger"; nonZero?: boolean; MIN_VALUE: MIN_VALUE; MAX_VALUE: MAX_VALUE; typeNameInMessage: string; }>) => OperatorsForInteger<ElementType, MIN_VALUE, MAX_VALUE>; type OperatorsForFloat<ElementType extends UnknownNumberBrand, MIN_VALUE extends number | undefined, MAX_VALUE extends number | undefined> = Readonly<{ MIN_VALUE: MIN_VALUE; MAX_VALUE: MAX_VALUE; is: (a: number) => a is ElementType; abs: (x: ElementType) => ToNonNegative<ElementType>; min: (...values: readonly ElementType[]) => ElementType; max: (...values: readonly ElementType[]) => ElementType; pow: (x: ElementType, y: ElementType) => ElementType; add: (x: ElementType, y: ElementType) => ElementType; sub: (x: ElementType, y: ElementType) => ElementType; mul: (x: ElementType, y: ElementType) => ElementType; div: (x: ElementType, y: ToNonZero<ElementType>) => ElementType; random: (min?: ElementType, max?: ElementType) => ElementType; randomNonZero: (min?: ElementType, max?: ElementType) => ElementType; castType: <N extends number>(x: N) => ElementType & N; clamp: TypeEq<MAX_VALUE | MIN_VALUE, undefined> extends true ? undefined : (x: number) => ElementType; }>; /** * Factory function that creates a complete set of type-safe operations for * floating-point types. * * This function generates: * * - Type guards and validators (checking for finite values) * - Arithmetic operations that preserve type constraints * - Utility functions (min, max, abs, random) * - Automatic clamping for bounded types * * All operations ensure results remain finite and within any specified * bounds. Division by zero is prevented through type constraints. * * @example * * ```ts * const floatOps = TsDataForgeInternals.RefinedNumberUtils.operatorsForFloat< * PositiveFiniteNumber, * number, * number * >({ * nonZero: true, * MIN_VALUE: Number.MIN_VALUE, * MAX_VALUE: Number.MAX_VALUE, * typeNameInMessage: 'PositiveFiniteNumber', * } as const); * * const fortyTwo = floatOps.castType(42.5); * * const seven = floatOps.castType(7.5); * * const sum = floatOps.add(fortyTwo, seven); * * const ratio = floatOps.div(sum, floatOps.castType(10)); * * const clamped = floatOps.clamp(0); * * const boundedRandom = floatOps.random( * floatOps.castType(10), * floatOps.castType(20), * ); * * const nonZeroRandom = floatOps.randomNonZero(); * * assert.isTrue(sum === 50); * * assert.isTrue(ratio === 5); * * assert.isTrue(clamped >= Number.MIN_VALUE); * * assert.isTrue(boundedRandom >= 10 && boundedRandom <= 20); * * assert.isTrue(nonZeroRandom > 0); * ``` * * @template ElementType - The floating-point branded type * @template MIN_VALUE - Optional minimum value for bounded types * @template MAX_VALUE - Optional maximum value for bounded types * @param config - Configuration object * @param config.nonZero - If true, excludes zero from valid values * @param config.MIN_VALUE - Minimum valid value (inclusive) * @param config.MAX_VALUE - Maximum valid value (inclusive) * @param config.typeNameInMessage - Human-readable type name for error * messages * @returns Object containing all type-safe operations for the * floating-point type * @internal */ export const operatorsForFloat: <ElementType extends UnknownNumberBrand, MIN_VALUE extends number, MAX_VALUE extends number>({ nonZero, MIN_VALUE, MAX_VALUE, typeNameInMessage, }: Readonly<{ nonZero?: boolean; MIN_VALUE: MIN_VALUE; MAX_VALUE: MAX_VALUE; typeNameInMessage: string; }>) => OperatorsForFloat<ElementType, MIN_VALUE, MAX_VALUE>; export {}; } } //# sourceMappingURL=refined-number-utils.d.mts.map