type-plus 7.4.0 → 7.5.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.
Files changed (192) hide show
  1. package/README.md +81 -92
  2. package/cjs/array/array.entries.d.ts +4 -3
  3. package/cjs/array/array.entries.d.ts.map +1 -1
  4. package/cjs/array/array_plus.common_prop_keys.d.ts +27 -0
  5. package/cjs/array/array_plus.common_prop_keys.d.ts.map +1 -0
  6. package/cjs/array/array_plus.common_prop_keys.js +3 -0
  7. package/cjs/array/array_plus.common_prop_keys.js.map +1 -0
  8. package/cjs/array/array_plus.d.ts +6 -3
  9. package/cjs/array/array_plus.d.ts.map +1 -1
  10. package/cjs/array/array_plus.drop_match.d.ts +4 -0
  11. package/cjs/array/array_plus.drop_match.d.ts.map +1 -0
  12. package/cjs/array/array_plus.drop_match.js +3 -0
  13. package/cjs/array/array_plus.drop_match.js.map +1 -0
  14. package/cjs/array/array_plus.element_match.d.ts +44 -0
  15. package/cjs/array/array_plus.element_match.d.ts.map +1 -0
  16. package/cjs/array/array_plus.element_match.js +3 -0
  17. package/cjs/array/array_plus.element_match.js.map +1 -0
  18. package/cjs/array/array_plus.find.d.ts +57 -0
  19. package/cjs/array/array_plus.find.d.ts.map +1 -0
  20. package/cjs/array/array_plus.find.js +3 -0
  21. package/cjs/array/array_plus.find.js.map +1 -0
  22. package/cjs/array/find_first.d.ts +62 -0
  23. package/cjs/array/find_first.d.ts.map +1 -0
  24. package/cjs/array/{array.find.js → find_first.js} +1 -1
  25. package/cjs/array/find_first.js.map +1 -0
  26. package/cjs/array/head.d.ts +18 -6
  27. package/cjs/array/head.d.ts.map +1 -1
  28. package/cjs/array/last.d.ts +17 -6
  29. package/cjs/array/last.d.ts.map +1 -1
  30. package/cjs/assertion/assert_type.d.ts +4 -1
  31. package/cjs/assertion/assert_type.d.ts.map +1 -1
  32. package/cjs/assertion/assert_type.js.map +1 -1
  33. package/cjs/index.d.ts +5 -2
  34. package/cjs/index.d.ts.map +1 -1
  35. package/cjs/index.js.map +1 -1
  36. package/cjs/never/never_type.d.ts +11 -0
  37. package/cjs/never/never_type.d.ts.map +1 -1
  38. package/cjs/object/index.d.ts +0 -1
  39. package/cjs/object/index.d.ts.map +1 -1
  40. package/cjs/object/index.js.map +1 -1
  41. package/cjs/testing/test_type.d.ts +277 -276
  42. package/cjs/testing/test_type.d.ts.map +1 -1
  43. package/cjs/testing/test_type.js.map +1 -1
  44. package/cjs/tuple/common_prop_keys.d.ts +15 -10
  45. package/cjs/tuple/common_prop_keys.d.ts.map +1 -1
  46. package/cjs/tuple/drop.d.ts +45 -26
  47. package/cjs/tuple/drop.d.ts.map +1 -1
  48. package/cjs/tuple/drop.js.map +1 -1
  49. package/cjs/tuple/tuple_plus.common_prop_keys.d.ts +28 -0
  50. package/cjs/tuple/tuple_plus.common_prop_keys.d.ts.map +1 -0
  51. package/cjs/tuple/tuple_plus.common_prop_keys.js +3 -0
  52. package/cjs/tuple/tuple_plus.common_prop_keys.js.map +1 -0
  53. package/cjs/tuple/tuple_plus.d.ts +3 -0
  54. package/cjs/tuple/tuple_plus.d.ts.map +1 -1
  55. package/cjs/tuple/tuple_plus.drop_match.d.ts +6 -0
  56. package/cjs/tuple/tuple_plus.drop_match.d.ts.map +1 -0
  57. package/cjs/tuple/tuple_plus.drop_match.js +3 -0
  58. package/cjs/tuple/tuple_plus.drop_match.js.map +1 -0
  59. package/cjs/tuple/tuple_plus.filter.d.ts +2 -2
  60. package/cjs/tuple/tuple_plus.find.d.ts +64 -0
  61. package/cjs/tuple/tuple_plus.find.d.ts.map +1 -0
  62. package/cjs/tuple/tuple_plus.find.js +3 -0
  63. package/cjs/tuple/tuple_plus.find.js.map +1 -0
  64. package/cjs/tuple/tuple_plus.pad_start.d.ts +7 -6
  65. package/cjs/tuple/tuple_plus.pad_start.d.ts.map +1 -1
  66. package/cjs/tuple/tuple_type.d.ts +41 -23
  67. package/cjs/tuple/tuple_type.d.ts.map +1 -1
  68. package/cjs/union/union.d.ts +33 -0
  69. package/cjs/union/union.d.ts.map +1 -0
  70. package/cjs/union/union.js +3 -0
  71. package/cjs/union/union.js.map +1 -0
  72. package/cjs/unknown/unknown_type.d.ts +12 -0
  73. package/cjs/unknown/unknown_type.d.ts.map +1 -1
  74. package/cjs/utils/options.d.ts +10 -0
  75. package/cjs/utils/options.d.ts.map +1 -0
  76. package/cjs/utils/options.js +3 -0
  77. package/cjs/utils/options.js.map +1 -0
  78. package/esm/array/array.entries.d.ts +4 -3
  79. package/esm/array/array.entries.d.ts.map +1 -1
  80. package/esm/array/array_plus.common_prop_keys.d.ts +27 -0
  81. package/esm/array/array_plus.common_prop_keys.d.ts.map +1 -0
  82. package/esm/array/array_plus.common_prop_keys.js +2 -0
  83. package/esm/array/array_plus.common_prop_keys.js.map +1 -0
  84. package/esm/array/array_plus.d.ts +6 -3
  85. package/esm/array/array_plus.d.ts.map +1 -1
  86. package/esm/array/array_plus.drop_match.d.ts +4 -0
  87. package/esm/array/array_plus.drop_match.d.ts.map +1 -0
  88. package/esm/array/array_plus.drop_match.js +2 -0
  89. package/esm/array/array_plus.drop_match.js.map +1 -0
  90. package/esm/array/array_plus.element_match.d.ts +44 -0
  91. package/esm/array/array_plus.element_match.d.ts.map +1 -0
  92. package/esm/array/array_plus.element_match.js +2 -0
  93. package/esm/array/array_plus.element_match.js.map +1 -0
  94. package/esm/array/array_plus.find.d.ts +57 -0
  95. package/esm/array/array_plus.find.d.ts.map +1 -0
  96. package/esm/array/array_plus.find.js +2 -0
  97. package/esm/array/array_plus.find.js.map +1 -0
  98. package/esm/array/find_first.d.ts +62 -0
  99. package/esm/array/find_first.d.ts.map +1 -0
  100. package/esm/array/find_first.js +2 -0
  101. package/esm/array/find_first.js.map +1 -0
  102. package/esm/array/head.d.ts +18 -6
  103. package/esm/array/head.d.ts.map +1 -1
  104. package/esm/array/last.d.ts +17 -6
  105. package/esm/array/last.d.ts.map +1 -1
  106. package/esm/assertion/assert_type.d.ts +4 -1
  107. package/esm/assertion/assert_type.d.ts.map +1 -1
  108. package/esm/assertion/assert_type.js.map +1 -1
  109. package/esm/index.d.ts +5 -2
  110. package/esm/index.d.ts.map +1 -1
  111. package/esm/index.js.map +1 -1
  112. package/esm/never/never_type.d.ts +11 -0
  113. package/esm/never/never_type.d.ts.map +1 -1
  114. package/esm/object/index.d.ts +0 -1
  115. package/esm/object/index.d.ts.map +1 -1
  116. package/esm/object/index.js.map +1 -1
  117. package/esm/testing/test_type.d.ts +277 -276
  118. package/esm/testing/test_type.d.ts.map +1 -1
  119. package/esm/testing/test_type.js.map +1 -1
  120. package/esm/tuple/common_prop_keys.d.ts +15 -10
  121. package/esm/tuple/common_prop_keys.d.ts.map +1 -1
  122. package/esm/tuple/drop.d.ts +45 -26
  123. package/esm/tuple/drop.d.ts.map +1 -1
  124. package/esm/tuple/drop.js.map +1 -1
  125. package/esm/tuple/tuple_plus.common_prop_keys.d.ts +28 -0
  126. package/esm/tuple/tuple_plus.common_prop_keys.d.ts.map +1 -0
  127. package/esm/tuple/tuple_plus.common_prop_keys.js +2 -0
  128. package/esm/tuple/tuple_plus.common_prop_keys.js.map +1 -0
  129. package/esm/tuple/tuple_plus.d.ts +3 -0
  130. package/esm/tuple/tuple_plus.d.ts.map +1 -1
  131. package/esm/tuple/tuple_plus.drop_match.d.ts +6 -0
  132. package/esm/tuple/tuple_plus.drop_match.d.ts.map +1 -0
  133. package/esm/tuple/tuple_plus.drop_match.js +2 -0
  134. package/esm/tuple/tuple_plus.drop_match.js.map +1 -0
  135. package/esm/tuple/tuple_plus.filter.d.ts +2 -2
  136. package/esm/tuple/tuple_plus.find.d.ts +64 -0
  137. package/esm/tuple/tuple_plus.find.d.ts.map +1 -0
  138. package/esm/tuple/tuple_plus.find.js +2 -0
  139. package/esm/tuple/tuple_plus.find.js.map +1 -0
  140. package/esm/tuple/tuple_plus.pad_start.d.ts +7 -6
  141. package/esm/tuple/tuple_plus.pad_start.d.ts.map +1 -1
  142. package/esm/tuple/tuple_type.d.ts +41 -23
  143. package/esm/tuple/tuple_type.d.ts.map +1 -1
  144. package/esm/union/union.d.ts +33 -0
  145. package/esm/union/union.d.ts.map +1 -0
  146. package/esm/union/union.js +2 -0
  147. package/esm/union/union.js.map +1 -0
  148. package/esm/unknown/unknown_type.d.ts +12 -0
  149. package/esm/unknown/unknown_type.d.ts.map +1 -1
  150. package/esm/utils/options.d.ts +10 -0
  151. package/esm/utils/options.d.ts.map +1 -0
  152. package/esm/utils/options.js +2 -0
  153. package/esm/utils/options.js.map +1 -0
  154. package/package.json +1 -1
  155. package/ts/array/array.entries.ts +4 -2
  156. package/ts/array/array_plus.common_prop_keys.ts +35 -0
  157. package/ts/array/array_plus.drop_match.ts +16 -0
  158. package/ts/array/array_plus.element_match.ts +61 -0
  159. package/ts/array/array_plus.find.ts +71 -0
  160. package/ts/array/array_plus.ts +6 -3
  161. package/ts/array/find_first.ts +71 -0
  162. package/ts/array/head.ts +28 -6
  163. package/ts/array/last.ts +26 -6
  164. package/ts/array/readme.md +128 -28
  165. package/ts/assertion/assert_type.ts +4 -1
  166. package/ts/assertion/readme.md +3 -2
  167. package/ts/index.ts +5 -5
  168. package/ts/never/never_type.ts +13 -0
  169. package/ts/object/index.ts +0 -1
  170. package/ts/testing/test_type.ts +279 -277
  171. package/ts/tuple/common_prop_keys.ts +18 -32
  172. package/ts/tuple/drop.ts +61 -60
  173. package/ts/tuple/readme.md +178 -39
  174. package/ts/tuple/tuple_plus.common_prop_keys.ts +47 -0
  175. package/ts/tuple/tuple_plus.drop_match.ts +20 -0
  176. package/ts/tuple/tuple_plus.filter.ts +2 -2
  177. package/ts/tuple/tuple_plus.find.ts +88 -0
  178. package/ts/tuple/tuple_plus.pad_start.ts +28 -25
  179. package/ts/tuple/tuple_plus.ts +3 -0
  180. package/ts/tuple/tuple_type.ts +67 -25
  181. package/ts/union/readme.md +81 -0
  182. package/ts/union/union.ts +37 -0
  183. package/ts/unknown/unknown_type.ts +13 -0
  184. package/ts/utils/options.ts +10 -0
  185. package/cjs/array/array.find.d.ts +0 -23
  186. package/cjs/array/array.find.d.ts.map +0 -1
  187. package/cjs/array/array.find.js.map +0 -1
  188. package/esm/array/array.find.d.ts +0 -23
  189. package/esm/array/array.find.d.ts.map +0 -1
  190. package/esm/array/array.find.js +0 -2
  191. package/esm/array/array.find.js.map +0 -1
  192. package/ts/array/array.find.ts +0 -34
@@ -0,0 +1,61 @@
1
+ import type { IsNever } from '../never/never_type.js'
2
+ import type { IsUnion } from '../union/union.js'
3
+ import type { MergeOptions } from '../utils/options.js'
4
+
5
+ /**
6
+ * 🦴 *utilities*
7
+ * 🔢 *customizable*
8
+ *
9
+ * Filter the element `T` in an array or tuple to match `Criteria`.
10
+ *
11
+ * @typeParam Options['widen'] Allow using narrow type to match widen type.
12
+ * e.g. `number, 1` -> `1 | undefined`.
13
+ * Default to `true`.
14
+ *
15
+ * @typeParam Options['caseNotMatch'] Return value when `T` does not match `Criteria`.
16
+ * Default to `never`.
17
+ *
18
+ * @typeParam Options['caseWiden'] Return value when `widen` is true.
19
+ * Default to `Criteria | undefined`.
20
+ *
21
+ * @typeParam Options['caseUnionNotMatch'] Return value when a branch of the union `T` does not match `Criteria`.
22
+ * Default to `never`.
23
+ *
24
+ * If you want the type to behave more like JavaScript,
25
+ * you can override it to return `undefined`.
26
+ *
27
+ * Since it is a union, the result will be joined to the matched branch as union.
28
+ * e.g. `ElementMatch<1 | 2, 1>` -> `1 | undefined`
29
+ */
30
+ export type ElementMatch<
31
+ T,
32
+ Criteria,
33
+ Options extends ElementMatch.Options = ElementMatch.DefaultOptions<Criteria>
34
+ > = [T] extends [Criteria]
35
+ ? T
36
+ : (MergeOptions<Options, ElementMatch.DefaultOptions<Criteria>> extends infer C extends Record<keyof ElementMatch.Options, unknown>
37
+ ? ((T extends Criteria
38
+ ? T
39
+ : (C['widen'] extends true
40
+ ? (Criteria extends T
41
+ ? C['caseWiden']
42
+ : C['caseNotMatch'])
43
+ : C['caseNotMatch'])) extends infer R
44
+ ? IsUnion<T, IsNever<R, R, R | C['caseUnionNotMatch']>, R>
45
+ : C['caseNotMatch'])
46
+ : never)
47
+
48
+ export namespace ElementMatch {
49
+ export interface Options {
50
+ widen?: boolean | undefined,
51
+ caseNotMatch?: unknown,
52
+ caseWiden?: unknown,
53
+ caseUnionNotMatch?: unknown
54
+ }
55
+ export interface DefaultOptions<Criteria> {
56
+ widen: true,
57
+ caseNotMatch: never,
58
+ caseWiden: Criteria | undefined,
59
+ caseUnionNotMatch: never
60
+ }
61
+ }
@@ -0,0 +1,71 @@
1
+ import type { NeverType } from '../never/never_type.js'
2
+ import type { TupleType } from '../tuple/tuple_type.js'
3
+ import type { MergeOptions } from '../utils/options.js'
4
+ import type { ElementMatch } from './array_plus.element_match.js'
5
+
6
+ /**
7
+ * 🦴 *utilities*
8
+ * 🔢 *customizable*
9
+ *
10
+ * Finds the type in array `A` that matches `Criteria`.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * type R = ArrayPlus.Find<Array<string>, string> // string
15
+ * type R = ArrayPlus.Find<Array<1 | 2 | 'x'>, number> // 1 | 2 | undefined
16
+ * type R = ArrayPlus.Find<Array<string | number>, number | string> // string | number
17
+ * type R = ArrayPlus.Find<Array<number>, 1> // widen: 1 | undefined
18
+ * type R = ArrayPlus.Find<Array<string | number>, number> // unionMiss: number | undefined
19
+ *
20
+ * type R = ArrayPlus.Find<string[], number> // never
21
+ * ```
22
+ *
23
+ * @typeParam Options['widen'] performs widen match.
24
+ * Default to `true`.
25
+ * With widen match, a narrowed type will match its widen type.
26
+ * e.g. matching `1` against `number` yields `1 | undefined`
27
+ *
28
+ * The widen behavior can be customized by `Options['caseWiden']`
29
+ *
30
+ * @typeParam Options['caseNever'] return type when `A` is `never`. Default to `never`.
31
+ *
32
+ * @typeParam Options['caseNotMatch'] Return value when `T` does not match `Criteria`.
33
+ * Default to `never`.
34
+ *
35
+ * @typeParam Options['caseTuple'] return type when `A` is a tuple. Default to `not supported` message.
36
+ *
37
+ * @typeParam Options['caseWiden'] return type when `T` in `A` is a widen type of `Criteria`.
38
+ * Default to `Criteria | undefined`.
39
+ * Set it to `never` for a more type-centric behavior
40
+ *
41
+ * @typeParam Options['caseUnionNotMatch'] Return value when a branch of the union `T` does not match `Criteria`.
42
+ * Default to `never`.
43
+ *
44
+ * If you want the type to behave more like JavaScript,
45
+ * you can override it to return `undefined`.
46
+ *
47
+ * Since it is a union, the result will be joined to the matched branch as union.
48
+ */
49
+ export type Find<
50
+ A extends unknown[],
51
+ Criteria,
52
+ Options extends Find.Options = Find.DefaultOptions<Criteria>
53
+ > =
54
+ MergeOptions<Options, Find.DefaultOptions<Criteria>> extends infer O extends Find.Options
55
+ ? TupleType<
56
+ A,
57
+ O['caseTuple'],
58
+ A extends Array<infer T> ? ElementMatch<T, Criteria, O> : never,
59
+ O
60
+ >
61
+ : never
62
+
63
+ export namespace Find {
64
+ export interface Options extends ElementMatch.Options, NeverType.Options {
65
+ caseTuple?: unknown,
66
+ }
67
+
68
+ export interface DefaultOptions<Criteria> extends ElementMatch.DefaultOptions<Criteria>, NeverType.DefaultOptions {
69
+ caseTuple: 'does not support tuple. Please use `FindFirst` or `TuplePlus.Find` instead.',
70
+ }
71
+ }
@@ -1,11 +1,14 @@
1
1
  export type { At } from './array.at.js'
2
- export type { Concat } from './array_plus.concat.js'
3
2
  export type { Entries } from './array.entries.js'
4
- export type { FindFirst as Find } from './array.find.js'
5
3
  export type { FindLast } from './array.find_last.js'
6
4
  export type { Reverse } from './array.reverse.js'
7
5
  export type { Some } from './array.some.js'
8
6
  export type { IndexAt, IsIndexOutOfBound } from './array_index.js'
7
+ export type { CommonPropKeys } from './array_plus.common_prop_keys.js'
8
+ export type { Concat } from './array_plus.concat.js'
9
+ export type { DropMatch } from './array_plus.drop_match.js'
10
+ export type { ElementMatch } from './array_plus.element_match.js'
9
11
  export type { Filter } from './array_plus.filter.js'
10
- export type { SplitAt } from './array_plus.split_at.js'
12
+ export type { Find } from './array_plus.find.js'
11
13
  export type { PadStart } from './array_plus.pad_start.js'
14
+ export type { SplitAt } from './array_plus.split_at.js'
@@ -0,0 +1,71 @@
1
+ import type { TupleType } from '../tuple/tuple_type.js'
2
+ import type { Find as TupleFind } from '../tuple/tuple_plus.find.js'
3
+ import type { Find as ArrayFind } from './array_plus.find.js'
4
+
5
+ /**
6
+ * 🦴 *utilities*
7
+ * 🔢 *customizable*
8
+ *
9
+ * Find the first type in the array or tuple `A` that matches `Criteria`.
10
+ *
11
+ * If the `Criteria` is not met, it will return `never'.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * type R = FindFirst<[true, 1, 'x', 3], string> // 'x'
16
+ * type R = FindFirst<[true, 1, 'x', 3], number> // 1
17
+ * type R = FindFirst<[string, number, 1], 1> // widen: 1 | undefined
18
+ * type R = FindFirst<[true, number | string], string> // unionMiss: string | undefined
19
+ * type R = FindFirst<Array<string>, string> // string
20
+ * type R = FindFirst<Array<1 | 2 | 'x'>, number> // 1 | 2 | undefined
21
+ * type R = FindFirst<Array<string | number>, number | string> // string | number
22
+ * type R = FindFirst<Array<number>, 1> // widen: 1 | undefined
23
+ * type R = FindFirst<Array<string | number>, number> // unionMiss: number | undefined
24
+ *
25
+ * type R = FindFirst<[true, 1, 'x'], 2> // never
26
+ * type R = FindFirst<string[], number> // never
27
+ * ```
28
+ *
29
+ * @typeParam Options['widen'] performs widen match.
30
+ * Default to `true`.
31
+ * With widen match, a narrowed type will match its widen type.
32
+ * e.g. matching `1` against `number` yields `1 | undefined`
33
+ *
34
+ * The widen behavior can be customized by `Options['caseWiden']`
35
+ *
36
+ * @typeParam Options['caseEmptyTuple'] return type when `A` is an empty tuple.
37
+ * Default to `never`.
38
+ *
39
+ * @typeParam Options['caseNever'] return type when `A` is `never`. Default to `never`.
40
+ *
41
+ * @typeParam Options['caseNoMatch'] Return value when `T` does not match `Criteria`.
42
+ * Default to `never`.
43
+ *
44
+ * @typeParam Options['caseWiden'] return type when `T` in `A` is a widen type of `Criteria`.
45
+ * Default to `Criteria | undefined`.
46
+ * Set it to `never` for a more type-centric behavior
47
+ *
48
+ * @typeParam Options['caseUnionMiss'] Return value when a branch of the union `T` does not match `Criteria`.
49
+ * Default to `undefined`.
50
+ * Since it is a union, the result will be join to the matched branch as union.
51
+ */
52
+ export type FindFirst<
53
+ A extends unknown[],
54
+ Criteria, Options extends FindFirst.Options = FindFirst.DefaultOptions<Criteria>
55
+ > = TupleType<
56
+ A,
57
+ TupleFind<A, Criteria, Options>,
58
+ ArrayFind<A, Criteria, Options>
59
+ >
60
+
61
+ export namespace FindFirst {
62
+ export interface Options extends ArrayFind.Options, TupleFind.Options { }
63
+ export interface DefaultOptions<Criteria>
64
+ extends ArrayFind.DefaultOptions<Criteria>, TupleFind.DefaultOptions<Criteria> { }
65
+ }
66
+
67
+
68
+ /**
69
+ * @deprecated use FindFirst
70
+ */
71
+ export type First<A extends any[], Criteria> = FindFirst<A, Criteria>
package/ts/array/head.ts CHANGED
@@ -1,7 +1,10 @@
1
+ import type { NeverType } from '../never/never_type.js'
2
+
1
3
  /**
2
4
  * 🦴 *utilities*
5
+ * 🔢 *customizable*
3
6
  *
4
- * Gets the first entry in the tuple or the type of array.
7
+ * Gets the first entry in the tuple or the type of array `T`.
5
8
  *
6
9
  * @example
7
10
  * ```ts
@@ -10,9 +13,28 @@
10
13
  *
11
14
  * type R = Head<[]> // never
12
15
  * ```
16
+ *
17
+ * @typeParam Options['caseNever'] Return type when `T` is `never`.
18
+ * Default to `never`.
19
+ *
20
+ * @typeParam Options['caseEmptyTuple'] Return type when `T` is `[]`.
21
+ * Default to `never`.
13
22
  */
14
- export type Head<T extends any[], Cases extends {
15
- empty_tuple?: unknown
16
- } = {
17
- empty_tuple: never
18
- }> = T['length'] extends 0 ? Cases['empty_tuple'] : T[0]
23
+ export type Head<
24
+ T extends unknown[],
25
+ Options extends Head.Options = Head.DefaultOptions
26
+ > = NeverType<
27
+ T,
28
+ Options['caseNever'],
29
+ T['length'] extends 0 ? Options['caseEmptyTuple'] : T[0]
30
+ >
31
+
32
+ export namespace Head {
33
+ export interface Options extends NeverType.Options {
34
+ caseEmptyTuple?: unknown
35
+ }
36
+
37
+ export interface DefaultOptions extends NeverType.DefaultOptions {
38
+ caseEmptyTuple: never
39
+ }
40
+ }
package/ts/array/last.ts CHANGED
@@ -1,7 +1,9 @@
1
+ import type { NeverType } from '../never/never_type.js'
2
+
1
3
  /**
2
4
  * 🦴 *utilities*
3
5
  *
4
- * Gets the last entry in the tuple or the type of array.
6
+ * Gets the last entry in the tuple or the type of array `T`.
5
7
  *
6
8
  * @example
7
9
  * ```ts
@@ -10,9 +12,27 @@
10
12
  *
11
13
  * type R = Last<[]> // never
12
14
  * ```
15
+ *
16
+ * @typeParam Options['caseNever'] Return type when `T` is `never`.
17
+ * Default to `never`.
18
+ *
19
+ * @typeParam Options['caseEmptyTuple'] Return type when `T` is `[]`.
20
+ * Default to `never`.
13
21
  */
14
- export type Last<T extends unknown[], Cases extends {
15
- empty_tuple?: unknown
16
- } = {
17
- empty_tuple: never
18
- }> = T['length'] extends 0 ? Cases['empty_tuple'] : T extends [...unknown[], infer R] ? R : T[0]
22
+ export type Last<
23
+ T extends unknown[],
24
+ Options extends Last.Options = Last.DefaultOptions
25
+ > = NeverType<T,
26
+ Options['caseNever'],
27
+ T['length'] extends 0 ? Options['caseEmptyTuple'] : T extends [...unknown[], infer R] ? R : T[0]
28
+ >
29
+
30
+ export namespace Last {
31
+ export interface Options extends NeverType.Options {
32
+ caseEmptyTuple?: unknown
33
+ }
34
+
35
+ export interface DefaultOptions extends NeverType.DefaultOptions {
36
+ caseEmptyTuple: never
37
+ }
38
+ }
@@ -12,7 +12,7 @@ and each element has the same type `T`.
12
12
  The `ArrayType<T>` and friends are used to check if a type is exactly `Array<T>` or not.
13
13
 
14
14
  They are strict type checks, meaning they match only the type `Array<T>`,
15
- and not [tuple], union, or intersection types.
15
+ and not [tuple], [union], or intersection types.
16
16
 
17
17
  ### [ArrayType](./array_type.ts#18)
18
18
 
@@ -83,7 +83,7 @@ type R = IsNotArrayType<number> // true
83
83
  type R = IsNotArrayType<[1]> // true
84
84
  ```
85
85
 
86
- ## [At](./array.at.ts)
86
+ ## [At](./array.at.ts#l20)
87
87
 
88
88
  `At<A, N, Fail = never>`
89
89
 
@@ -97,7 +97,7 @@ as there is no way to guarantee the array has value at `N`.
97
97
  ```ts
98
98
  type A = Array<string | number>
99
99
 
100
- ArrayPlus.At<A, 0> // string | number | undefined
100
+ type R = ArrayPlus.At<A, 0> // string | number | undefined
101
101
  ```
102
102
 
103
103
  For tuple, it will return the type of the tuple value at index `N`.
@@ -105,8 +105,8 @@ For tuple, it will return the type of the tuple value at index `N`.
105
105
  ```ts
106
106
  type T = [number, string, 1, 2, 3]
107
107
 
108
- ArrayPlus.At<T, 0> // number
109
- ArrayPlus.At<T, -1> // 3
108
+ type R = ArrayPlus.At<T, 0> // number
109
+ type R = ArrayPlus.At<T, -1> // 3
110
110
  ```
111
111
 
112
112
  If the `N` is out of bound,
@@ -127,9 +127,41 @@ It is added for completeness.
127
127
 
128
128
  You are encouraged to use `[...A, ...B]` directly.
129
129
 
130
- ## [`FindFirst`](./array.find.ts)
130
+ ## [`FindFirst`](./find_first.ts#l52)
131
131
 
132
- ## [`FineLast`](./array.find_last.ts)
132
+ `FindFirst<A, Criteria, Options = { widen, caseEmptyTuple, caseNever, caseNoMatch, caseWiden, caseUnionMiss }>`
133
+
134
+ 🦴 *utilities*
135
+ 🔢 *customizable*
136
+
137
+ Find the first type in the array or tuple `A` that matches `Criteria`.
138
+
139
+ ```ts
140
+ import type { FindFirst } from 'type-plus'
141
+
142
+ type R = FindFirst<[true, 1, 'x', 3], string> // 'x'
143
+ type R = FindFirst<[true, 1, 'x', 3], number> // 1
144
+ type R = FindFirst<[string, number, 1], 1> // widen: 1 | undefined
145
+ type R = FindFirst<[true, number | string], string> // unionNotMatch: string
146
+ type R = FindFirst<Array<string>, string> // string
147
+ type R = FindFirst<Array<1 | 2 | 'x'>, number> // 1 | 2 | undefined
148
+ type R = FindFirst<Array<string | number>, number | string> // string | number
149
+ type R = FindFirst<Array<number>, 1> // widen: 1 | undefined
150
+ type R = FindFirst<Array<string | number>, number> // unionNotMatch: number
151
+
152
+ type R = FindFirst<[true, 1, 'x'], 2> // never
153
+ type R = FindFirst<string[], number> // never
154
+
155
+ // customization
156
+ type R = FindFirst<[number], 1, { widen: false }> // never
157
+ type R = FindFirst<[number], 1, { caseWiden: never }> // never
158
+ type R = FindFirst<[], 1, { caseEmptyTuple: 2 }> // 2
159
+ type R = FindFirst<never, 1, { caseNever: 2 }> // 2
160
+ type R = FindFirst<[string], number, { caseNotMatch: 2 }> // 2
161
+ type R = FindFirst<[string | number], number, { caseUnionNotMatch: undefined }> // number | undefined
162
+ ```
163
+
164
+ ## [`FindLast`](./array.find_last.ts)
133
165
 
134
166
  ## [`Some`](./array.some.ts)
135
167
 
@@ -164,42 +196,52 @@ type R = KeepMatch<[1, 2, '3'], number> // [1, 2]
164
196
  type R = KeepMatch<Array<string | undefined>, string> // string[]
165
197
  ```
166
198
 
167
- ## [`Head`](./head.ts#l14)
199
+ ## [`Head`](./head.ts#l23)
168
200
 
169
- `Head<T, Cases = { empty_tuple }>`
201
+ `Head<T, Options = { caseNever, caseEmptyTuple }>`
170
202
 
171
203
  🦴 *utilities*
204
+ 🔢 *customizable*
172
205
 
173
- Gets the first entry in the tuple or the type of array.
206
+ Gets the first entry in the tuple or the type of array `T`.
174
207
 
175
208
  ```ts
176
209
  import type { Head } from 'type-plus'
177
210
 
178
211
  type R = Head<[1, 2, 3]> // 1
179
212
  type R = Head<string[]> // string
213
+ type R = Head<never> // caseNever: never
214
+ type R = Head<[]> // caseEmptyTuple: never
180
215
 
181
- type R = Head<[]> // never
216
+ // customization
217
+ type R = Head<never, { caseNever: 1 }> // 1
218
+ type R = Head<[], { caseEmptyTuple: undefined }> // undefined
182
219
  ```
183
220
 
184
221
  ## [`IntersectOfProps`](./intersect_of_props.ts)
185
222
 
186
223
  ## [`MapToProp`](./intersect_of_props.ts)
187
224
 
188
- ## [`Last`](./last.ts)
225
+ ## [`Last`](./last.ts#l23)
189
226
 
190
- `Last<T, Cases = { empty_tuple }>`
227
+ `Last<T, Options = { caseNever, caseEmptyTuple }>`
191
228
 
192
229
  🦴 *utilities*
230
+ 🔢 *customizable*
193
231
 
194
- Gets the last entry in the tuple or the type of array.
232
+ Gets the last entry in the tuple or the type of array `T`.
195
233
 
196
234
  ```ts
197
235
  import type { Last } from 'type-plus'
198
236
 
199
237
  type R = Last<[1, 2, 3]> // 3
200
238
  type R = Last<string[]> // string
239
+ type R = Last<never> // caseNever: never
240
+ type R = Last<[]> // caseEmptyTuple: never
201
241
 
202
- type R = Last<[]> // never
242
+ // customization
243
+ type R = Last<never, { caseNever: 1 }> // 1
244
+ type R = Last<[], { caseEmptyTuple: undefined }> // undefined
203
245
  ```
204
246
 
205
247
  ## [`literalArray`](./literal_array.ts)
@@ -231,12 +273,56 @@ please check [`TuplePlus`](../tuple/readme.md#TuplePlus).
231
273
 
232
274
  Alias of [At](#at).
233
275
 
234
- ### [`ArrayPlus.Concat`](./array.concat.ts#L12)
276
+ ## [ArrayPlus.CommonPropKeys](./array_plus.common_prop_keys.ts#l21)
277
+
278
+ `ArrayPlus.CommonPropKeys<T extends Record[], Options = { caseNever }>`
279
+
280
+ ⚗️ *transform*
281
+ 🔢 *customizable*
282
+
283
+ Gets the common property keys of the elements in array `A`.
284
+
285
+ ```ts
286
+ import { type ArrayPlus } from 'type-plus'
287
+
288
+ type R = ArrayPlus.CommonPropKeys<Array<{ a: 1 }>> // 'a'
289
+ type R = ArrayPlus.CommonPropKeys<Array<{ a: 1, b: 1 } | { a: 1, c: 1 }>> // 'a'
290
+
291
+ // customization
292
+ type R = ArrayPlus.CommonPropKeys<never, { caseNever: 1 }> // 1
293
+ ```
294
+
295
+ ### [`ArrayPlus.Concat`](./array.concat.ts#l12)
235
296
 
236
297
  `ArrayPlus.Concat<A, B>`
237
298
 
238
299
  Alias of [Concat](#concat).
239
300
 
301
+ ### [`ArrayPlus.ElementMatch`](./array_plus.element_match.ts#l30)
302
+
303
+ `ArrayPlus.ElementMatch<T, Criteria, Options = { widen, caseNotMatch, caseWiden, caseUnionNotMatch }>`
304
+
305
+ 🌪️ *filter*
306
+ 🔢 *customizable*
307
+
308
+ Filter the element `T` in an array or tuple to match `Criteria`.
309
+
310
+ ```ts
311
+ import type { ArrayPlus } from 'type-plus'
312
+
313
+ type R = ArrayPlus.ElementMatch<number, number> // number
314
+ type R = ArrayPlus.ElementMatch<1, number> // 1
315
+ type R = ArrayPlus.ElementMatch<number, string> // notMatch: never
316
+ type R = ArrayPlus.ElementMatch<number, 1> // widen: 1
317
+ type R = ArrayPlus.ElementMatch<number | string, number> // unionNotMatch: number
318
+
319
+ // customization
320
+ type R = ArrayPlus.ElementMatch<number, string, { caseNotMatch: 1 }> // 1
321
+ type R = ArrayPlus.ElementMatch<number, 1, { widen: false }> // never
322
+ type R = ArrayPlus.ElementMatch<number, 1, { caseWiden: never }> // never
323
+ type R = ArrayPlus.ElementMatch<number | string, number, { caseUnionNotMatch: undefined }> // number | undefined
324
+ ```
325
+
240
326
  ### [`ArrayPlus.Entries`](./array.entries.ts#L14)
241
327
 
242
328
  > `ArrayPlus.Entries<A>`
@@ -247,24 +333,37 @@ Note that this is not the same as `Array.entries(A)`,
247
333
  which returns an iterable interator.
248
334
 
249
335
  ```ts
250
- ArrayPlus.Entries<Array<string | number>> // Array<[number, string | number]>
251
- ArrayPlus.Entries<[1, 2, 3]> // [[0, 1], [1, 2], [2, 3]]
336
+ type R = ArrayPlus.Entries<Array<string | number>> // Array<[number, string | number]>
337
+ type R = ArrayPlus.Entries<[1, 2, 3]> // [[0, 1], [1, 2], [2, 3]]
252
338
  ```
253
339
 
254
- ### [`ArrayPlus.Find`](./array.find.ts#L17)
340
+ ### [`ArrayPlus.Find`](./array_plus.find.ts#l49)
255
341
 
256
- > `ArrayPlus.Find<A, Criteria>
342
+ `ArrayPlus.Find<A, Criteria, Options { widen, caseNever, caseNotMatch, caseTuple, caseWiden, caseUnionNotMatch }>`
257
343
 
258
- Returns the first type in the array or tuple that matches the `Criteria`.
259
-
260
- If the `Criteria` is not met, it will return `never'.
344
+ 🦴 *utilities*
345
+ 🔢 *customizable*
261
346
 
262
- For `Array<T>`, it will return `T | undefined` if `T` satisfies `Criteria`.
347
+ Finds the type in array `A` that matches `Criteria`.
263
348
 
264
349
  ```ts
265
- ArrayPlus.Find<Array<1 | 2 | 'x'>, number> // 1 | 2 | undefined
266
-
267
- ArrayPlus.Find<[true, 1, 'x', 3], string> // 'x'
350
+ import type { ArrayPlus } from 'type-plus'
351
+
352
+ type R = ArrayPlus.Find<Array<string>, string> // string
353
+ type R = ArrayPlus.Find<Array<1 | 2 | 'x'>, number> // 1 | 2 | undefined
354
+ type R = ArrayPlus.Find<Array<string | number>, number | string> // string | number
355
+ type R = ArrayPlus.Find<number[], 1> // widen: 1 | undefined
356
+ type R = ArrayPlus.Find<Array<string | number>, number> // unionNotMatch: number
357
+
358
+ type R = ArrayPlus.Find<string[], number> // never
359
+
360
+ // customization
361
+ type R = ArrayPlus.Find<number[], 1, { widen: false }> // never
362
+ type R = ArrayPlus.Find<number[], 1, { caseWiden: never }> // never
363
+ type R = ArrayPlus.Find<never, 1, { caseNever: 2 }> // 2
364
+ type R = ArrayPlus.Find<string[], number, { caseNotMatch: 2 }> // 2
365
+ type R = ArrayPlus.Find<[], 1, { caseTuple: 2 }> // 2
366
+ type R = ArrayPlus.Find<Array<string | number>, number, { caseUnionNotMatch: undefined }> // number | undefined
268
367
  ```
269
368
 
270
369
  ### [`ArrayPlus.FindLast`](./array.find_last.ts#L17)
@@ -339,7 +438,7 @@ or with reduced capability.
339
438
  They are exposed under the `ArrayPlus` namespace,
340
439
  while some common ones are exposed at top-level.
341
440
 
342
- Here are the list of array methods and their corresponding type-level functions, if availableL
441
+ Here are the list of array methods and their corresponding type-level functions, if available.
343
442
 
344
443
  - ✅ `at`: [`ArrayPlus.At`](#arrayplusat)
345
444
  - ✅ `concat`: [`Concat` | `ArrayPlus.Concat`](#arrayplusconcat) (`[...A, ...B]`)
@@ -375,3 +474,4 @@ Here are the list of array methods and their corresponding type-level functions,
375
474
 
376
475
  [handbook]: https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#arrays
377
476
  [tuple]: ../tuple/readme.md
477
+ [union]: ../union/readme.md
@@ -3,7 +3,10 @@ import { isConstructor, type AnyConstructor } from '../class/index.js'
3
3
  import { type AnyFunction } from '../function/any_function.js'
4
4
 
5
5
  /**
6
- * assert the subject satisfies the specified type T
6
+ * 💥 *immediate*
7
+ * 🚦 *assertion*
8
+ *
9
+ * Assert the subject satisfies the specified type T
7
10
  * @type T the type to check against.
8
11
  */
9
12
  export function assertType<T>(subject: T): asserts subject is T
@@ -9,11 +9,12 @@ They throw an error if the condition is not met, and return nothing otherwise.
9
9
  These assertion functions are typically used in runtime,
10
10
  so that that type of the value can be narrowed down.
11
11
 
12
- ## [assertType](./assert_type.ts)
12
+ ## [assertType](./assert_type.ts#l10)
13
13
 
14
14
  `assertType<T>(subject)`
15
15
 
16
- 💥 `immediate`
16
+ 💥 *immediate*
17
+ 🚦 *assertion*
17
18
 
18
19
  It ensures `subject` satisfies `T`.
19
20
  It is similar to `const x: T = subject` without introducing an unused variable.
package/ts/index.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  export type { AnyType, IsAny, IsNotAny, NotAnyType } from './any/any_type.js'
2
2
  export type { At } from './array/array.at.js'
3
- export type { FindFirst } from './array/array.find.js'
4
3
  export type { FindLast } from './array/array.find_last.js'
5
4
  export type { Some } from './array/array.some.js'
6
5
  export type { Concat } from './array/array_plus.concat.js'
7
6
  export * as ArrayPlus from './array/array_plus.js'
8
7
  export type { ArrayType, IsArray, IsNotArray, NotArrayType } from './array/array_type.js'
9
8
  export type { Filter, KeepMatch } from './array/filter.js'
9
+ export type { FindFirst } from './array/find_first.js'
10
10
  export type { Head } from './array/head.js'
11
11
  export type { IntersectOfProps, MapToProp } from './array/intersect_of_props.js'
12
12
  export type { Last } from './array/last.js'
@@ -77,6 +77,7 @@ export type {
77
77
  Zero
78
78
  } from './numeric/numeric_type.js'
79
79
  export type { IsNotPositive, IsPositive, NonPositive, Positive } from './numeric/positive.js'
80
+ export type { Required, RequiredExcept, RequiredPick } from './object/Required.js'
80
81
  export * from './object/index.js'
81
82
  export type { IsNotObject, IsObject, NotObjectType, ObjectType } from './object/object_type.js'
82
83
  export * from './predicates/index.js'
@@ -94,7 +95,7 @@ export type { IsNotString, IsString, NotStringType, StringType } from './string/
94
95
  export type { IsNotSymbol, IsSymbol, NotSymbolType, SymbolType } from './symbol/symbol_type.js'
95
96
  export * from './testing/stub.js'
96
97
  export * from './testing/test_type.js'
97
- export type { CommonPropKeys } from './tuple/common_prop_keys.js'
98
+ export type { CommonKeys, CommonPropKeys } from './tuple/common_prop_keys.js'
98
99
  export * from './tuple/create_tuple.js'
99
100
  export { drop } from './tuple/drop.js'
100
101
  export type { DropFirst, DropLast, DropMatch, DropNull, DropNullable, DropUndefined } from './tuple/drop.js'
@@ -110,12 +111,11 @@ export type {
110
111
  NotUndefinedType,
111
112
  UndefinedType
112
113
  } from './undefined/undefined_type.js'
114
+ export type { IsUnion, UnionType } from './union/union.js'
113
115
  export type { UnionKeys } from './union_keys.js'
114
116
  export type { IsNotUnknown, IsUnknown, NotUnknownType, UnknownType } from './unknown/unknown_type.js'
115
117
  export * from './unpartial.js'
116
118
  export * from './utils/index.js'
119
+ export type { MergeOptions as MergeCases } from './utils/options.js'
117
120
  export type { IsNotVoid, IsVoid, NotVoidType, VoidType } from './void/void_type.js'
118
121
 
119
-
120
-
121
-
@@ -55,3 +55,16 @@ export type IsNever<T, Then = true, Else = false> = NeverType<T, Then, Else>
55
55
  * type R = IsNotNever<never> // false
56
56
  */
57
57
  export type IsNotNever<T, Then = true, Else = false> = NeverType<T, Else, Then>
58
+
59
+ export namespace NeverType {
60
+ /**
61
+ * Type options when input type is `never`.
62
+ */
63
+ export interface Options {
64
+ caseNever?: unknown
65
+ }
66
+
67
+ export interface DefaultOptions {
68
+ caseNever: never
69
+ }
70
+ }
@@ -12,7 +12,6 @@ export type { Partial, PartialExcept, PartialOmit, PartialPick } from './Partial
12
12
  export type * from './optional_key.js'
13
13
  export type { RecursiveIntersect } from './RecursiveIntersect.js'
14
14
  export type { RecursiveRequired } from './RecursiveRequired.js'
15
- export type { RequiredExcept, RequiredPick } from './Required.js'
16
15
  export type { RequiredKeys } from './RequiredKeys.js'
17
16
  export type { SpreadRecord } from './SpreadRecord.js'
18
17
  export type { ValueOf } from './ValueOf.js'