@rimbu/typical
Version:
Type-level numeric and string operations
351 lines (327 loc) • 7.72 kB
text/typescript
import type { StrNum, U } from './index.mts';
/**
* Returns the sum of given numbers.
* @note due to compiler limitations, the maximum result and input numbers is 9999.
* @example
* ```ts
* Add<13, 25> => 38
* Add<1386, 335> => 1721
* ```
*/
export type Add<N1 extends number, N2 extends number> = StrNum.ToNumber<
StrNum.Add<StrNum.FromNumber<N1>, StrNum.FromNumber<N2>>
>;
/**
* Returns true if the given number is positive (> 0), false otherwise
* @example
* ```ts
* IsPositive<9> => true
* IsPositive<0> => false
* IsPositive<-5> => false
* ```
*/
export type IsPositive<N extends number> = GreaterThanOrEqual<N, 1>;
/**
* Returns true if the given number is a natural number (>= 0), false otherwise
* @example
* ```ts
* IsNatural<9> => true
* IsNatural<0> => true
* IsNatural<-5> => false
* ```
*/
export type IsNatural<N extends number> = GreaterThanOrEqual<N, 0>;
/**
* Returns true if the given number is negative (< 0), false otherwise.
* @example
* ```ts
* IsNegative<9> => false
* IsNegative<0> => false
* IsNegative<-5> => true
* ```
*/
export type IsNegative<N extends number> = U.Not<IsNatural<N>>;
/**
* Returns the result of subtracting N2 from N1.
* @note since only natural numbers are supported, a result that would be negative will be type never.
* @note due to compiler limitations, the maximum result and input numbers is 9999.
* @example
* ```ts
* Subtract<25, 13> => 12
* Subtract<1721, 335> => 1386
* Subtract<5, 8> => never
* ```
*/
export type Subtract<N1 extends number, N2 extends number> = N1 extends never
? never
: N2 extends never
? never
: StrNum.ToNumber<
StrNum.Subtract<StrNum.FromNumber<N1>, StrNum.FromNumber<N2>>
>;
/**
* Add 1 to the given natural number.
* @example
* ```ts
* Inc<4> => 5
* Inc<312> => 313
* Inc<-3> => never
* ```
*/
export type Inc<N extends number> = Add<N, 1>;
/**
* Decreases a positive number by 1, or if the number is not positive,
* returns never.
* @example
* ```ts
* Dec<5> => 4
* Dec<434> => 433
* Dec<0> => never
* ```
*/
export type Decr<N extends number> = Subtract<N, 1>;
/**
* Returns true if the given natural number is even, or never otherwise.
* @example
* ```ts
* Even<4> => true
* Even<11> => false
* Even<-3> => never
* ```
*/
export type IsEven<N extends number> = StrNum.IsEven<StrNum.FromNumber<N>>;
/**
* Returns true if the given natural number is odd, or never otherwise.
* @example
* ```ts
* Odd<4> => false
* Odd<11> => true
* Odd<-3> => never
* ```
*/
export type IsOdd<N extends number> = StrNum.IsOdd<StrNum.FromNumber<N>>;
/**
* Returns the smallest of the given 2 natural numbers, of never otherwise
* @example
* ```ts
* Min<2, 5> => 2
* Min<534, 424> => 424
* Min<-4, 4> => never
* ```
*/
export type Min<N1 extends number, N2 extends number> = N1 extends never
? never
: N2 extends never
? never
: Subtract<N1 & U.Check<N1>, N2 & U.Check<N2>> extends never
? N1
: N2;
/**
* Returns the largest of the given 2 natural numbers, of never otherwise
* @example
* ```ts
* Max<2, 5> => 5
* Max<534, 424> => 534
* Max<-4, 4> => never
* ```
*/
export type Max<N1 extends number, N2 extends number> = N1 extends never
? never
: N2 extends never
? never
: Subtract<N1, N2> extends never
? N2
: N1;
/**
* Returns true if the given numbers are equal.
* @example
* ```ts
* Equal<0, 0> => true
* Equal<8, 9> => false
* ```
*/
export type Equal<N1 extends number, N2 extends number> = N1 extends N2
? N2 extends N1
? true
: false
: false;
/**
* Returns true if the given numbers are not equal.
* @example
* ```ts
* NotEqual<0, 0> => false
* NotEqual<8, 9> => true
* ```
*/
export type NotEqual<N1 extends number, N2 extends number> = N1 extends N2
? N1 extends N2
? false
: true
: true;
/**
* Returns true if the given first natural number is greater or equal than the second.
* Returns never otherwise.
* @example
* ```ts
* GreaterThanOrEqual<15, 12> => true
* GreaterThanOrEqual<15, 6> => never
* ```
*/
export type GreaterThanOrEqual<N1 extends number, N2 extends number> = Subtract<
N1,
N2
> extends never
? false
: true;
/**
* Returns true if the first given number is greater than the second.
* @example
* ```ts
* GreaterThan<5, 5> => false
* GreaterThan<8, 5> => true
* GreaterThan<3, 7> => false
* ```
*/
export type GreaterThan<N1 extends number, N2 extends number> = N1 extends N2
? false
: GreaterThanOrEqual<N1, N2>;
/**
* Returns true if the first given number is less than the second.
* @example
* ```ts
* LessThan<5, 5> => false
* LessThan<8, 5> => false
* LessThan<3, 7> => true
* ```
*/
export type LessThan<N1 extends number, N2 extends number> = Subtract<
N1,
N2
> extends never
? true
: false;
/**
* Returns true if the first given number is less than or equal to the second.
* @example
* ```ts
* LessThanOrEqual<5, 5> => true
* LessThanOrEqual<8, 5> => false
* LessThanOrEqual<3, 7> => true
* ```
*/
export type LessThanOrEqual<
N1 extends number,
N2 extends number
> = N1 extends N2 ? true : LessThan<N1, N2>;
/**
* Returns true if the given number is greater than or equal to given L, and less than
* or equal to given H, and returns false otherwise.
* @example
* ```ts
* InRange<4, 5, 10> => false
* InRange<6, 5, 10> => true
* InRange<5, 5, 10> => true
* ```
*/
export type InRange<
N extends number,
L extends number,
H extends number
> = GreaterThanOrEqual<N, L> & LessThanOrEqual<N, H> extends never
? false
: true;
/**
* Returns the result of multiplying the given natural numbers.
* @example
* ```ts
* Mult<0, 0> => 0
* Mult<9, 10> => 90
* Mult<3, 18> => 54
* ```
*/
export type Mult<N1 extends number, N2 extends number> = N1 extends 0
? 0
: N2 extends 0
? 0
: N1 extends 1
? N2
: N2 extends 1
? N1
: StrNum.ToNumber<StrNum.Mult<StrNum.FromNumber<N1>, StrNum.FromNumber<N2>>>;
/**
* Returns a tuple containing the quotient and remainer of dividing the first number
* by the second.
* @example
* ```ts
* DivMod<9, 5> => [1, 4]
* DivMod<9, 3> => [3, 0]
* ```
*/
export type DivMod<N1 extends number, N2 extends number> = N2 extends 0
? never
: N1 extends 0
? [0, 0]
: N1 extends N2
? [1, 0]
: StrNum.Divide<StrNum.FromNumber<N1>, StrNum.FromNumber<N2>> extends [
infer Q,
infer R
]
? [StrNum.ToNumber<string & Q>, StrNum.ToNumber<string & R>]
: never;
/**
* Returns the result of dividing the first given natural number by the second.
* @example
* ```ts
* Div<0, 0> => never
* Div<9, 3> => 3
* Div<14, 5> => 2
* ```
*/
export type Div<N1 extends number, N2 extends number> = N2 extends 0
? never
: N1 extends 0
? 0
: N1 extends N2
? 1
: StrNum.ToNumber<
StrNum.Divide<StrNum.FromNumber<N1>, StrNum.FromNumber<N2>>[0]
>;
/**
* Returns the remainder after dividing the first given natural number by the second.
* @example
* ```ts
* Mod<0, 0> => never
* Mod<9, 3> => 0
* Mod<14, 5> => 4
* ```
*/
export type Mod<N1 extends number, N2 extends number> = N2 extends 0
? never
: N1 extends 0
? 0
: N1 extends N2
? 0
: StrNum.ToNumber<
StrNum.Divide<StrNum.FromNumber<N1>, StrNum.FromNumber<N2>>[1]
>;
/**
* Returns the power of the first natural number to the second given natural number.
* @example
* ```ts
* Pow<2, 0> => 1
* Pow<2, 3> => 8
* Pow<3, 4> => 81
* ```
*/
export type Pow<N1 extends number, N2 extends number> = N1 extends 0
? 0
: N2 extends 0
? 1
: N2 extends 1
? N1
: N2 extends 2
? Mult<N1, N1>
: IsEven<N2> extends true
? Pow<Mult<N1, N1>, Div<N2, 2>>
: Mult<N1, Pow<N1, Decr<N2>>>;