type-plus 4.8.2 → 4.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -415,8 +415,8 @@ So you may encounter some weird behavior if your logic is complex.
415
415
  - `Abs<N, Fail=never>`: `Abs(N)`, `Abs<number>` returns `Fail`.
416
416
  - `IsPositive<N>`: is `N` a positive number literal. `IsPositive<number>` returns `false`.
417
417
  - `IsWhole<N>`: is `N` a whole number literal. `IsWhole<number>` returns `false`.
418
- - `Max<A, B, Fail=never>`: `max(A, B)`, for positive and whole number, `Fail` otherwise.
419
- - `GreaterThan<A, B, Fail=never>`: `A > B` for positive and whole numbers, `Fail` otherwise.
418
+ - `Max<A, B, Fail=never>`: `max(A, B)`, for whole number, `Fail` otherwise.
419
+ - `GreaterThan<A, B, Fail=never>`: `A > B` for whole numbers, `Fail` otherwise.
420
420
 
421
421
  #### Arithmetics
422
422
 
@@ -48,6 +48,8 @@ export declare namespace DigitArray {
48
48
  type ToTuple<R extends any[], S extends number[], X = any> = S['length'] extends 0 ? R : (S['length'] extends 1 ? [...R, ...Digit.ToTuple<X>[S[0]]] : (S extends [any, ...infer T] ? (T extends any[] ? ToTuple<Multi10<[...R, ...Digit.ToTuple<X>[S[0]]]>, T> : never) : never));
49
49
  type Multi10<C extends any[]> = [...C, ...C, ...C, ...C, ...C, ...C, ...C, ...C, ...C, ...C];
50
50
  type FromNumber<N extends number> = FromString<NumberToString<N>>;
51
+ type FromNumberAbs<N extends number> = FromString<TrimMinusSign<`${N}`>>;
52
+ type TrimMinusSign<N extends string> = N extends `-${infer rest}` ? rest : N;
51
53
  type NumberToString<N extends number> = (And<IsPositive<N>, IsWhole<N>>) extends true ? `${N}` : never;
52
54
  type FromString<S extends string> = S extends `1${infer L}` ? [1, ...FromString<L>] : S extends `2${infer L}` ? [2, ...FromString<L>] : S extends `3${infer L}` ? [3, ...FromString<L>] : S extends `4${infer L}` ? [4, ...FromString<L>] : S extends `5${infer L}` ? [5, ...FromString<L>] : S extends `6${infer L}` ? [6, ...FromString<L>] : S extends `7${infer L}` ? [7, ...FromString<L>] : S extends `8${infer L}` ? [8, ...FromString<L>] : S extends `9${infer L}` ? [9, ...FromString<L>] : S extends `0${infer L}` ? [0, ...FromString<L>] : [];
53
55
  type Shift10<DA extends number[]> = TrimLeadingZero<Shift10State<[], DA>>;
@@ -1,11 +1,11 @@
1
1
  import type { Head, PadLeft, Tail } from '../array';
2
- import type { And, Equal } from '../predicates';
2
+ import type { And, Equal, Or, Xor } from '../predicates';
3
3
  import type { Digit, DigitArray } from './Digit';
4
4
  import type { IsPositive } from './IsPositive';
5
5
  import type { IsWhole } from './IsWhole';
6
6
  import type { Max } from './Max';
7
- export declare type GreaterThan<A extends number, B extends number, Fail = never> = And<And<IsPositive<A>, IsWhole<A>>, And<IsPositive<B>, IsWhole<B>>> extends false ? Fail : number extends A ? Fail : number extends B ? Fail : Equal<A, B> extends true ? false : GreaterThan.OnPositiveWhole<A, B>;
7
+ export declare type GreaterThan<A extends number, B extends number, Fail = never> = And<IsWhole<A>, IsWhole<B>> extends false ? Fail : number extends A ? Fail : number extends B ? Fail : Equal<A, B> extends true ? false : Xor<IsPositive<A>, IsPositive<B>> extends true ? IsPositive<A> : Or<IsPositive<A>, IsPositive<B>> extends false ? GreaterThan.ForWholeNumber<B, A> : GreaterThan.ForWholeNumber<A, B>;
8
8
  export declare namespace GreaterThan {
9
- type OnPositiveWhole<A extends number, B extends number> = (DigitArray.FromNumber<A> extends infer DA ? DA extends number[] ? DigitArray.FromNumber<B> extends infer DB ? DB extends number[] ? Max<DA['length'], DB['length']> extends infer M ? M extends number ? PadLeft<DA, M, 0> extends infer PDA ? PDA extends number[] ? PadLeft<DB, M, 0> extends infer PDB ? PDB extends number[] ? OnDigitArray<PDA, PDB> : never : never : never : never : never : never : never : never : never : never);
10
- type OnDigitArray<DA extends number[], DB extends number[]> = (Equal<Head<DA>, Head<DB>> extends true ? OnDigitArray<Tail<DA>, Tail<DB>> : Digit.GreaterThan<Head<DA>, Head<DB>>);
9
+ type ForWholeNumber<A extends number, B extends number> = (DigitArray.FromNumberAbs<A> extends infer DA ? DA extends number[] ? DigitArray.FromNumberAbs<B> extends infer DB ? DB extends number[] ? Max<DA['length'], DB['length']> extends infer M ? M extends number ? PadLeft<DA, M, 0> extends infer PDA ? PDA extends number[] ? PadLeft<DB, M, 0> extends infer PDB ? PDB extends number[] ? ForDigitArray<PDA, PDB> : never : never : never : never : never : never : never : never : never : never);
10
+ type ForDigitArray<DA extends number[], DB extends number[]> = (Equal<Head<DA>, Head<DB>> extends true ? ForDigitArray<Tail<DA>, Tail<DB>> : Digit.GreaterThan<Head<DA>, Head<DB>>);
11
11
  }
package/cjs/math/Max.d.ts CHANGED
@@ -1,10 +1,3 @@
1
- import type { Head, Tail } from '../array';
2
- import type { And, Equal } from '../predicates';
3
- import type { Digit, DigitArray } from './Digit';
4
- import type { IsPositive } from './IsPositive';
5
- import type { IsWhole } from './IsWhole';
6
- export declare type Max<A extends number, B extends number, Fail = never> = And<IsPositive<A>, IsWhole<A>> extends false ? Fail : And<IsPositive<B>, IsWhole<B>> extends false ? Fail : number extends A ? Fail : number extends B ? Fail : Equal<A, B> extends true ? A : Max.OnPositiveWhole<A, B>;
7
- export declare namespace Max {
8
- type OnPositiveWhole<A extends number, B extends number> = (DigitArray.FromNumber<A> extends infer DA ? DA extends number[] ? DigitArray.FromNumber<B> extends infer DB ? DB extends number[] ? OnDigitArray<DA, DB> extends DA ? A : B : never : never : never : never);
9
- type OnDigitArray<DA extends number[], DB extends number[]> = Equal<DA['length'], DB['length']> extends true ? (Equal<Head<DA>, Head<DB>> extends true ? (Tail<DA> extends infer TDA ? TDA extends number[] ? OnDigitArray<TDA, Tail<DB>> extends TDA ? DA : DB : never : never) : Digit.GreaterThan<Head<DA>, Head<DB>> extends true ? DA : DB) : OnPositiveWhole<DA['length'], DB['length']> extends DA['length'] ? DA : DB;
10
- }
1
+ import type { Equal } from '../predicates';
2
+ import { GreaterThan } from './GreaterThan';
3
+ export declare type Max<A extends number, B extends number, Fail = never> = GreaterThan<A, B> extends infer Result ? Equal<Result, never> extends true ? Fail : Result extends true ? A : B : never;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "type-plus",
3
- "version": "4.8.2",
3
+ "version": "4.9.0",
4
4
  "description": "Provides additional types for TypeScript.",
5
5
  "homepage": "https://github.com/unional/type-plus",
6
6
  "bugs": {
package/ts/math/Digit.ts CHANGED
@@ -66,6 +66,8 @@ export namespace DigitArray {
66
66
 
67
67
 
68
68
  export type FromNumber<N extends number> = FromString<NumberToString<N>>
69
+ export type FromNumberAbs<N extends number> = FromString<TrimMinusSign<`${N}`>>
70
+ export type TrimMinusSign<N extends string> = N extends `-${infer rest}` ? rest : N
69
71
 
70
72
  export type NumberToString<N extends number> = (And<IsPositive<N>, IsWhole<N>>) extends true ? `${N}` : never
71
73
 
@@ -1,10 +1,8 @@
1
1
  import { GreaterThan, isType } from '..'
2
2
 
3
- test('only support positive and whole number', () => {
3
+ test('only support whole number', () => {
4
4
  isType.equal<true, never, GreaterThan<0.1, 1>>()
5
- isType.equal<true, never, GreaterThan<-1, 1>>()
6
5
  isType.equal<true, never, GreaterThan<1, 0.1>>()
7
- isType.equal<true, never, GreaterThan<1, -1>>()
8
6
  })
9
7
 
10
8
  test('number gets never', () => {
@@ -13,31 +11,65 @@ test('number gets never', () => {
13
11
  })
14
12
 
15
13
  test('override Fail case', () => {
16
- isType.equal<true, number, GreaterThan<number, 1, number>>()
14
+ isType.equal<true, number, GreaterThan<number, 2, number>>()
17
15
  })
18
16
 
19
17
  test('n > n is false', () => {
20
- isType.f<GreaterThan<0, 0>>()
21
- isType.f<GreaterThan<1, 1>>()
22
- isType.f<GreaterThan<12, 12>>()
18
+ isType.equal<true, false, GreaterThan<0, 0>>()
19
+ isType.equal<true, false, GreaterThan<1, 1>>()
20
+ isType.equal<true, false, GreaterThan<12, 12>>()
23
21
  })
24
22
 
25
23
  test('with same number of digits', () => {
26
- isType.t<GreaterThan<1, 0>>()
27
- isType.t<GreaterThan<22, 11>>()
28
- isType.t<GreaterThan<20, 19>>()
29
- isType.t<GreaterThan<19, 10>>()
24
+ isType.equal<true, true, GreaterThan<1, 0>>()
25
+ isType.equal<true, true, GreaterThan<22, 11>>()
26
+ isType.equal<true, true, GreaterThan<20, 19>>()
27
+ isType.equal<true, true, GreaterThan<19, 10>>()
30
28
 
31
- isType.f<GreaterThan<0, 1>>()
32
- isType.f<GreaterThan<11, 22>>()
33
- isType.f<GreaterThan<19, 20>>()
34
- isType.f<GreaterThan<10, 19>>()
29
+ isType.equal<true, false, GreaterThan<0, 1>>()
30
+ isType.equal<true, false, GreaterThan<11, 22>>()
31
+ isType.equal<true, false, GreaterThan<19, 20>>()
32
+ isType.equal<true, false, GreaterThan<10, 19>>()
35
33
  })
36
34
 
37
35
  test('with different number of digits', () => {
38
- isType.f<GreaterThan<0, 1>>()
39
- isType.f<GreaterThan<9, 100>>()
40
- isType.t<GreaterThan<10, 1>>()
41
- isType.t<GreaterThan<123, 32>>()
42
- isType.t<GreaterThan<123, 13>>()
36
+ isType.equal<true, false, GreaterThan<0, 1>>()
37
+ isType.equal<true, false, GreaterThan<9, 100>>()
38
+ isType.equal<true, true, GreaterThan<10, 1>>()
39
+ isType.equal<true, true, GreaterThan<123, 32>>()
40
+ isType.equal<true, true, GreaterThan<123, 13>>()
41
+ })
42
+
43
+ test('-0 > 0 and 0 > -0 are false', () => {
44
+ isType.equal<true, false, GreaterThan<-0, 0>>()
45
+ isType.equal<true, false, GreaterThan<0, -0>>()
46
+ })
47
+
48
+ test('works with negative numbers', () => {
49
+ isType.equal<true, true, GreaterThan<0, -1>>()
50
+ isType.equal<true, true, GreaterThan<1, -1>>()
51
+ isType.equal<true, true, GreaterThan<2, -1>>()
52
+
53
+ isType.equal<true, false, GreaterThan<-1, 0>>()
54
+ isType.equal<true, false, GreaterThan<-1, 1>>()
55
+ isType.equal<true, false, GreaterThan<-1, 2>>()
56
+
57
+ isType.equal<true, false, GreaterThan<-0, -0>>()
58
+ isType.equal<true, false, GreaterThan<-1, -1>>()
59
+
60
+ isType.equal<true, true, GreaterThan<-0, -1>>()
61
+ isType.equal<true, false, GreaterThan<-1, -1>>()
62
+ isType.equal<true, false, GreaterThan<-2, -1>>()
63
+
64
+ isType.equal<true, false, GreaterThan<-1, -0>>()
65
+ isType.equal<true, false, GreaterThan<-1, -1>>()
66
+ isType.equal<true, true, GreaterThan<-1, -2>>()
67
+ })
68
+
69
+ test('work with large numbers', () => {
70
+ isType.equal<true, true, GreaterThan<1000000, 0>>()
71
+ isType.equal<true, false, GreaterThan<0, 1000000>>()
72
+
73
+ isType.equal<true, false, GreaterThan<-1000000, 0>>()
74
+ isType.equal<true, true, GreaterThan<0, -1000000>>()
43
75
  })
@@ -1,28 +1,27 @@
1
1
  import type { Head, PadLeft, Tail } from '../array'
2
- import type { And, Equal } from '../predicates'
2
+ import type { And, Equal, Or, Xor } from '../predicates'
3
3
  import type { Digit, DigitArray } from './Digit'
4
4
  import type { IsPositive } from './IsPositive'
5
5
  import type { IsWhole } from './IsWhole'
6
6
  import type { Max } from './Max'
7
7
 
8
8
  export type GreaterThan<A extends number, B extends number, Fail = never> =
9
- And<
10
- And<IsPositive<A>, IsWhole<A>>,
11
- And<IsPositive<B>, IsWhole<B>>
12
- > extends false ? Fail :
9
+ And<IsWhole<A>, IsWhole<B>> extends false ? Fail :
13
10
  number extends A ? Fail :
14
11
  number extends B ? Fail :
15
12
  Equal<A, B> extends true ? false :
16
- GreaterThan.OnPositiveWhole<A, B>
13
+ Xor<IsPositive<A>, IsPositive<B>> extends true ? IsPositive<A> :
14
+ Or<IsPositive<A>, IsPositive<B>> extends false ? GreaterThan.ForWholeNumber<B, A> :
15
+ GreaterThan.ForWholeNumber<A, B>
17
16
 
18
17
  export namespace GreaterThan {
19
- export type OnPositiveWhole<A extends number, B extends number> = (
20
- DigitArray.FromNumber<A> extends infer DA ? DA extends number[] ?
21
- DigitArray.FromNumber<B> extends infer DB ? DB extends number[] ?
18
+ export type ForWholeNumber<A extends number, B extends number> = (
19
+ DigitArray.FromNumberAbs<A> extends infer DA ? DA extends number[] ?
20
+ DigitArray.FromNumberAbs<B> extends infer DB ? DB extends number[] ?
22
21
  Max<DA['length'], DB['length']> extends infer M ? M extends number ?
23
22
  PadLeft<DA, M, 0> extends infer PDA ? PDA extends number[] ?
24
23
  PadLeft<DB, M, 0> extends infer PDB ? PDB extends number[] ?
25
- OnDigitArray<PDA, PDB>
24
+ ForDigitArray<PDA, PDB>
26
25
  : never : never
27
26
  : never : never
28
27
  : never : never
@@ -30,9 +29,9 @@ export namespace GreaterThan {
30
29
  : never : never
31
30
  )
32
31
 
33
- export type OnDigitArray<DA extends number[], DB extends number[]> = (
32
+ export type ForDigitArray<DA extends number[], DB extends number[]> = (
34
33
  Equal<Head<DA>, Head<DB>> extends true
35
- ? OnDigitArray<Tail<DA>, Tail<DB>>
34
+ ? ForDigitArray<Tail<DA>, Tail<DB>>
36
35
  : Digit.GreaterThan<Head<DA>, Head<DB>>
37
36
  )
38
37
  }
@@ -1,35 +1,59 @@
1
- import { isType, Max } from '..'
2
-
3
- test('only support positive and whole number', () => {
4
- isType.equal<true, never, Max<0.1, 1>>()
5
- isType.equal<true, never, Max<-1, 1>>()
6
- isType.equal<true, never, Max<1, 0.1>>()
7
- isType.equal<true, never, Max<1, -1>>()
8
- })
9
-
10
- test('number gets never', () => {
11
- isType.equal<true, never, Max<number, 1>>()
12
- isType.equal<true, never, Max<1, number>>()
13
- })
14
-
15
- test('override Fail case', () => {
16
- isType.equal<true, number, Max<number, 1, number>>()
17
- })
18
-
19
- test('same number', () => {
20
- isType.equal<true, 123, Max<123, 123>>()
21
- })
22
-
23
- test('same number of digits', () => {
24
- isType.equal<true, 124, Max<123, 124>>()
25
- isType.equal<true, 126, Max<126, 124>>()
26
- isType.equal<true, 224, Max<126, 224>>()
27
- isType.equal<true, 726, Max<726, 224>>()
28
- })
29
-
30
- test('more digits win', () => {
31
- isType.equal<true, 123, Max<123, 22>>()
32
- isType.equal<true, 223, Max<12, 223>>()
33
- isType.equal<true, 1234567891011, Max<1234567891011, 123>>()
34
- isType.equal<true, 1234567891011, Max<123, 1234567891011>>()
35
- })
1
+ import { isType, Max } from '..'
2
+
3
+ test('only support whole number', () => {
4
+ isType.equal<true, never, Max<0.1, 1>>()
5
+ isType.equal<true, never, Max<1, 0.1>>()
6
+ })
7
+
8
+ test('number gets never', () => {
9
+ isType.equal<true, never, Max<number, 1>>()
10
+ isType.equal<true, never, Max<1, number>>()
11
+ })
12
+
13
+ test('override Fail case', () => {
14
+ isType.equal<true, number, Max<number, 1, number>>()
15
+ })
16
+
17
+ test('same number', () => {
18
+ isType.equal<true, 123, Max<123, 123>>()
19
+ })
20
+
21
+ test('same number of digits', () => {
22
+ isType.equal<true, 124, Max<123, 124>>()
23
+ isType.equal<true, 126, Max<126, 124>>()
24
+ isType.equal<true, 224, Max<126, 224>>()
25
+ isType.equal<true, 726, Max<726, 224>>()
26
+ })
27
+
28
+ test('more digits win', () => {
29
+ isType.equal<true, 123, Max<123, 22>>()
30
+ isType.equal<true, 223, Max<12, 223>>()
31
+ isType.equal<true, 1234567891011, Max<1234567891011, 123>>()
32
+ isType.equal<true, 1234567891011, Max<123, 1234567891011>>()
33
+ })
34
+
35
+ test('work with negative numbers', () => {
36
+ isType.equal<true, 0, Max<0, -0>>()
37
+ isType.equal<true, 0, Max<-0, 0>>()
38
+ isType.equal<true, 0, Max<-0, -0>>()
39
+
40
+ isType.equal<true, 0, Max<0, -1>>()
41
+ isType.equal<true, 1, Max<1, -1>>()
42
+ isType.equal<true, 2, Max<2, -1>>()
43
+
44
+ isType.equal<true, 0, Max<-1, 0>>()
45
+ isType.equal<true, 1, Max<-1, 1>>()
46
+ isType.equal<true, 2, Max<-1, 2>>()
47
+
48
+ isType.equal<true, -1, Max<-1, -2>>()
49
+ isType.equal<true, -2, Max<-2, -2>>()
50
+ isType.equal<true, -2, Max<-3, -2>>()
51
+ })
52
+
53
+ test('work with large numbers', () => {
54
+ isType.equal<true, 1000000, Max<1000000, 0>>()
55
+ isType.equal<true, 1000000, Max<0, 1000000>>()
56
+
57
+ isType.equal<true, 0, Max<-1000000, 0>>()
58
+ isType.equal<true, 0, Max<0, -1000000>>()
59
+ })
package/ts/math/Max.ts CHANGED
@@ -1,32 +1,8 @@
1
- import type { Head, Tail } from '../array'
2
- import type { And, Equal } from '../predicates'
3
- import type { Digit, DigitArray } from './Digit'
4
- import type { IsPositive } from './IsPositive'
5
- import type { IsWhole } from './IsWhole'
1
+ import type { Equal } from '../predicates'
2
+ import { GreaterThan } from './GreaterThan'
6
3
 
7
4
  export type Max<A extends number, B extends number, Fail = never> =
8
- And<IsPositive<A>, IsWhole<A>> extends false ? Fail :
9
- And<IsPositive<B>, IsWhole<B>> extends false ? Fail :
10
- number extends A ? Fail :
11
- number extends B ? Fail :
12
- Equal<A, B> extends true ? A :
13
- Max.OnPositiveWhole<A, B>
14
-
15
- export namespace Max {
16
- export type OnPositiveWhole<A extends number, B extends number> = (
17
- DigitArray.FromNumber<A> extends infer DA ? DA extends number[] ?
18
- DigitArray.FromNumber<B> extends infer DB ? DB extends number[] ?
19
- OnDigitArray<DA, DB> extends DA ? A : B
20
- : never : never
21
- : never : never
22
- )
23
-
24
- export type OnDigitArray<DA extends number[], DB extends number[]> =
25
- Equal<DA['length'], DB['length']> extends true
26
- ? (Equal<Head<DA>, Head<DB>> extends true
27
- ? (Tail<DA> extends infer TDA ? TDA extends number[] ?
28
- OnDigitArray<TDA, Tail<DB>> extends TDA ? DA : DB
29
- : never : never)
30
- : Digit.GreaterThan<Head<DA>, Head<DB>> extends true ? DA : DB)
31
- : OnPositiveWhole<DA['length'], DB['length']> extends DA['length'] ? DA : DB
32
- }
5
+ GreaterThan<A, B> extends infer Result ?
6
+ Equal<Result, never> extends true ? Fail :
7
+ Result extends true ? A : B
8
+ : never