import { IndexOfHighestNumber, TupleOf } from './Array'; import { Not, Or } from './Boolean'; import { Includes, PadStart, StartsWith, Tail, ToString } from './String'; import { Equals } from './misc'; import { ListOf } from 'ts-toolbelt/out/Union/ListOf'; type _PrependNextNum> = A['length'] extends infer T ? [T, ...A] extends [...infer X] ? X : never : never; type _Enumerate, N extends number> = number extends N ? number[] : N extends A['length'] ? A : _Enumerate<_PrependNextNum, N>; /** * creates a union type of numbers from 0 to generic `N` * @example * type Foo = Enumerate<3> //0|1|2 * @see https://stackoverflow.com/a/63918062 */ export type Enumerate = _Enumerate<[], N>[never]; /** * creates a range type of numbers from generics `FROM` (inclusive) to `TO` (inclusive) * @example * type Foo = RangeType<2, 5> //2|3|4|5 * @see https://stackoverflow.com/a/63918062 */ export type RangeType = Exclude, Enumerate> | TO; /** * adds two `number` types together * @example * type Foo = Add<2, 3> //5 */ export type Add = [ ...TupleOf, ...TupleOf ]['length'] & number; /** * subtracts `N2` from `N1` * @example * type Foo = Subtract<5, 2> //3 */ export type Subtract = TupleOf extends readonly [ ...TupleOf, ...infer R ] ? R['length'] : never; type _MultiAdd = IterationsLeft extends 0 ? Accumulator : _MultiAdd, Decrement>; /** * multiplies `N1` by `N2` * * **WARNING**: currently fails on big numbers * @example * type Foo = Multiply<2, 3> //6 * @see https://itnext.io/implementing-arithmetic-within-typescripts-type-system-a1ef140a6f6f */ export type Multiply = number extends N1 | N2 ? number : { [K2 in N2]: { [K1 in N1]: _MultiAdd; }[N1]; }[N2]; type _AtTerminus = Dividee extends 0 ? true : Divider extends 0 ? true : false; type _LessThanTerminus = _AtTerminus extends true ? Equals extends true ? false : Dividee extends 0 ? true : false : _LessThanTerminus, Decrement>; type _MultiSub = _LessThanTerminus extends true ? QuotientAccumulator : _MultiSub, Divider, Increment>; /** * divides `N1` by `N2` * * **WARNING**: currently fails on big numbers * @example * type Foo = Divide<6, 3> //2 * @see https://itnext.io/implementing-arithmetic-within-typescripts-type-system-a1ef140a6f6f */ export type Divide = number extends N1 | N2 ? number : { [K2 in N2]: { [K1 in N1]: _MultiSub; }[N1]; }[N2]; /** * gets the remainder of `Divide` * @example * type Foo = Modulo<7, 4> //3 * @see https://itnext.io/implementing-arithmetic-within-typescripts-type-system-a1ef140a6f6f */ export type Modulo = _LessThanTerminus extends true ? N1 : Modulo, N2>; type PowerTailRec = number extends PowerOf ? number : PowerOf extends 0 ? Result : PowerTailRec, Multiply>; /** * raises the value of `Num` to the power of the `PowerOf` parameter. */ export type Power = PowerTailRec; /** * raises the value of `Num` to the power of 2 */ export type Square = Power; type FactorialTailRec = T extends 1 ? Result : FactorialTailRec, Multiply>; export type Factorial = number extends T ? number : FactorialTailRec; /** * checks whether a number is positive or negative */ export type IsPositive = `${T}` extends `-${number}` ? false : true; /** * adds 1 to `T` */ export type Increment = Add; /** subtracts 1 from `T` */ export type Decrement = Subtract; /** * adds leading zeros to a number until it reaches a specified length * @example * type Foo = LeadingZeros<12, 5> //'00012' * type Bar = LeadingZeros<-12, 5> //'-00012' */ export type LeadingZeros = number extends Num | Length ? ToString : IsPositive extends true ? PadStart, Length, '0'> : `-${PadStart>, Length, '0'>}`; /** * creates a stringified ordinal value for the given number * @example * type First = Ordinal<1> //1st * type Third = Ordinal<3> //3rd */ export type Ordinal = number extends T ? `${number}${'st' | 'nd' | 'rd' | 'th'}` : { [Num in T]: `${Num}${Modulo extends infer Mod ? Mod extends 1 ? 'st' : Mod extends 2 ? 'nd' : Mod extends 3 ? 'rd' : 'th' : never}`; }[T]; /** `true` if `Num1` is greater than `Num2`, else `false` */ export type IsGreaterThan = { [Num1 in Num1s]: { [Num2 in Num2s]: TupleOf extends [never, ...TupleOf, ...never[]] ? true : false; }[Num2s]; }[Num1s]; export type IsGreaterOrEqual = { [Num1 in Num1s]: { [Num2 in Num2s]: Or | Equals>; }[Num2s]; }[Num1s]; export type IsLessThan = { [Num1 in Num1s]: { [Num2 in Num2s]: Not>; }[Num2s]; }[Num1s]; export type IsLessOrEqual = Not>; /** gets the highest number in a union of numbers */ export type HighestNumber = ListOf[IndexOfHighestNumber>]; /** shifts the bits of `Num` left by the given `Count` */ export type LeftShift = Multiply>; /** shifts the bits of `Num` right by the given `Count` */ export type RightShift = Divide>; /** * a `number` that cannot have a decimal * @example * declare const foo = (num: Integer): void * foo(1) //no error * foo(1.2) //error */ export type Integer = number extends T ? never : Includes<`${T}`, '.'> extends true ? never : T; /** * a `number` that can only be positive * @example * declare const foo = (num: PositiveNumber): void * foo(1) //no error * foo(-1) //error */ export type PositiveNumber = number extends T ? never : StartsWith<`${T}`, '-'> extends true ? never : T; /** * a `number` that can only be negative * @example * declare const foo = (num: NegativeNumber): void * foo(-1) //no error * foo(1) //error */ export type NegativeNumber = number extends T ? never : PositiveNumber extends never ? T : never; export type StringifiedNumber = `${number}` | `${'-' | '+' | ''}Infinity`; export type ToNumber = T extends `${infer Result extends number}` ? Result : T extends StringifiedNumber ? number : undefined | (string extends T ? number : never); export {}; //# sourceMappingURL=Number.d.ts.map