type-plus 7.4.0 → 7.6.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 (202) 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_index.d.ts +4 -1
  5. package/cjs/array/array_index.d.ts.map +1 -1
  6. package/cjs/array/array_plus.common_prop_keys.d.ts +27 -0
  7. package/cjs/array/array_plus.common_prop_keys.d.ts.map +1 -0
  8. package/cjs/array/array_plus.common_prop_keys.js +3 -0
  9. package/cjs/array/array_plus.common_prop_keys.js.map +1 -0
  10. package/cjs/array/array_plus.d.ts +6 -3
  11. package/cjs/array/array_plus.d.ts.map +1 -1
  12. package/cjs/array/array_plus.drop_match.d.ts +4 -0
  13. package/cjs/array/array_plus.drop_match.d.ts.map +1 -0
  14. package/cjs/array/array_plus.drop_match.js +3 -0
  15. package/cjs/array/array_plus.drop_match.js.map +1 -0
  16. package/cjs/array/array_plus.element_match.d.ts +44 -0
  17. package/cjs/array/array_plus.element_match.d.ts.map +1 -0
  18. package/cjs/array/array_plus.element_match.js +3 -0
  19. package/cjs/array/array_plus.element_match.js.map +1 -0
  20. package/cjs/array/array_plus.find.d.ts +57 -0
  21. package/cjs/array/array_plus.find.d.ts.map +1 -0
  22. package/cjs/array/array_plus.find.js +3 -0
  23. package/cjs/array/array_plus.find.js.map +1 -0
  24. package/cjs/array/array_plus.split_at.d.ts +20 -15
  25. package/cjs/array/array_plus.split_at.d.ts.map +1 -1
  26. package/cjs/array/find_first.d.ts +62 -0
  27. package/cjs/array/find_first.d.ts.map +1 -0
  28. package/cjs/array/{array.find.js → find_first.js} +1 -1
  29. package/cjs/array/find_first.js.map +1 -0
  30. package/cjs/array/head.d.ts +18 -6
  31. package/cjs/array/head.d.ts.map +1 -1
  32. package/cjs/array/last.d.ts +17 -6
  33. package/cjs/array/last.d.ts.map +1 -1
  34. package/cjs/assertion/assert_type.d.ts +4 -1
  35. package/cjs/assertion/assert_type.d.ts.map +1 -1
  36. package/cjs/assertion/assert_type.js.map +1 -1
  37. package/cjs/index.d.ts +5 -2
  38. package/cjs/index.d.ts.map +1 -1
  39. package/cjs/index.js.map +1 -1
  40. package/cjs/never/never_type.d.ts +11 -0
  41. package/cjs/never/never_type.d.ts.map +1 -1
  42. package/cjs/object/index.d.ts +0 -1
  43. package/cjs/object/index.d.ts.map +1 -1
  44. package/cjs/object/index.js.map +1 -1
  45. package/cjs/testing/test_type.d.ts +277 -276
  46. package/cjs/testing/test_type.d.ts.map +1 -1
  47. package/cjs/testing/test_type.js.map +1 -1
  48. package/cjs/tuple/common_prop_keys.d.ts +15 -10
  49. package/cjs/tuple/common_prop_keys.d.ts.map +1 -1
  50. package/cjs/tuple/drop.d.ts +45 -26
  51. package/cjs/tuple/drop.d.ts.map +1 -1
  52. package/cjs/tuple/drop.js.map +1 -1
  53. package/cjs/tuple/tuple_plus.common_prop_keys.d.ts +28 -0
  54. package/cjs/tuple/tuple_plus.common_prop_keys.d.ts.map +1 -0
  55. package/cjs/tuple/tuple_plus.common_prop_keys.js +3 -0
  56. package/cjs/tuple/tuple_plus.common_prop_keys.js.map +1 -0
  57. package/cjs/tuple/tuple_plus.d.ts +3 -0
  58. package/cjs/tuple/tuple_plus.d.ts.map +1 -1
  59. package/cjs/tuple/tuple_plus.drop_match.d.ts +6 -0
  60. package/cjs/tuple/tuple_plus.drop_match.d.ts.map +1 -0
  61. package/cjs/tuple/tuple_plus.drop_match.js +3 -0
  62. package/cjs/tuple/tuple_plus.drop_match.js.map +1 -0
  63. package/cjs/tuple/tuple_plus.filter.d.ts +2 -2
  64. package/cjs/tuple/tuple_plus.find.d.ts +64 -0
  65. package/cjs/tuple/tuple_plus.find.d.ts.map +1 -0
  66. package/cjs/tuple/tuple_plus.find.js +3 -0
  67. package/cjs/tuple/tuple_plus.find.js.map +1 -0
  68. package/cjs/tuple/tuple_plus.pad_start.d.ts +7 -6
  69. package/cjs/tuple/tuple_plus.pad_start.d.ts.map +1 -1
  70. package/cjs/tuple/tuple_type.d.ts +41 -23
  71. package/cjs/tuple/tuple_type.d.ts.map +1 -1
  72. package/cjs/union/union.d.ts +33 -0
  73. package/cjs/union/union.d.ts.map +1 -0
  74. package/cjs/union/union.js +3 -0
  75. package/cjs/union/union.js.map +1 -0
  76. package/cjs/unknown/unknown_type.d.ts +12 -0
  77. package/cjs/unknown/unknown_type.d.ts.map +1 -1
  78. package/cjs/utils/options.d.ts +10 -0
  79. package/cjs/utils/options.d.ts.map +1 -0
  80. package/cjs/utils/options.js +3 -0
  81. package/cjs/utils/options.js.map +1 -0
  82. package/esm/array/array.entries.d.ts +4 -3
  83. package/esm/array/array.entries.d.ts.map +1 -1
  84. package/esm/array/array_index.d.ts +4 -1
  85. package/esm/array/array_index.d.ts.map +1 -1
  86. package/esm/array/array_plus.common_prop_keys.d.ts +27 -0
  87. package/esm/array/array_plus.common_prop_keys.d.ts.map +1 -0
  88. package/esm/array/array_plus.common_prop_keys.js +2 -0
  89. package/esm/array/array_plus.common_prop_keys.js.map +1 -0
  90. package/esm/array/array_plus.d.ts +6 -3
  91. package/esm/array/array_plus.d.ts.map +1 -1
  92. package/esm/array/array_plus.drop_match.d.ts +4 -0
  93. package/esm/array/array_plus.drop_match.d.ts.map +1 -0
  94. package/esm/array/array_plus.drop_match.js +2 -0
  95. package/esm/array/array_plus.drop_match.js.map +1 -0
  96. package/esm/array/array_plus.element_match.d.ts +44 -0
  97. package/esm/array/array_plus.element_match.d.ts.map +1 -0
  98. package/esm/array/array_plus.element_match.js +2 -0
  99. package/esm/array/array_plus.element_match.js.map +1 -0
  100. package/esm/array/array_plus.find.d.ts +57 -0
  101. package/esm/array/array_plus.find.d.ts.map +1 -0
  102. package/esm/array/array_plus.find.js +2 -0
  103. package/esm/array/array_plus.find.js.map +1 -0
  104. package/esm/array/array_plus.split_at.d.ts +20 -15
  105. package/esm/array/array_plus.split_at.d.ts.map +1 -1
  106. package/esm/array/find_first.d.ts +62 -0
  107. package/esm/array/find_first.d.ts.map +1 -0
  108. package/esm/array/find_first.js +2 -0
  109. package/esm/array/find_first.js.map +1 -0
  110. package/esm/array/head.d.ts +18 -6
  111. package/esm/array/head.d.ts.map +1 -1
  112. package/esm/array/last.d.ts +17 -6
  113. package/esm/array/last.d.ts.map +1 -1
  114. package/esm/assertion/assert_type.d.ts +4 -1
  115. package/esm/assertion/assert_type.d.ts.map +1 -1
  116. package/esm/assertion/assert_type.js.map +1 -1
  117. package/esm/index.d.ts +5 -2
  118. package/esm/index.d.ts.map +1 -1
  119. package/esm/index.js.map +1 -1
  120. package/esm/never/never_type.d.ts +11 -0
  121. package/esm/never/never_type.d.ts.map +1 -1
  122. package/esm/object/index.d.ts +0 -1
  123. package/esm/object/index.d.ts.map +1 -1
  124. package/esm/object/index.js.map +1 -1
  125. package/esm/testing/test_type.d.ts +277 -276
  126. package/esm/testing/test_type.d.ts.map +1 -1
  127. package/esm/testing/test_type.js.map +1 -1
  128. package/esm/tuple/common_prop_keys.d.ts +15 -10
  129. package/esm/tuple/common_prop_keys.d.ts.map +1 -1
  130. package/esm/tuple/drop.d.ts +45 -26
  131. package/esm/tuple/drop.d.ts.map +1 -1
  132. package/esm/tuple/drop.js.map +1 -1
  133. package/esm/tuple/tuple_plus.common_prop_keys.d.ts +28 -0
  134. package/esm/tuple/tuple_plus.common_prop_keys.d.ts.map +1 -0
  135. package/esm/tuple/tuple_plus.common_prop_keys.js +2 -0
  136. package/esm/tuple/tuple_plus.common_prop_keys.js.map +1 -0
  137. package/esm/tuple/tuple_plus.d.ts +3 -0
  138. package/esm/tuple/tuple_plus.d.ts.map +1 -1
  139. package/esm/tuple/tuple_plus.drop_match.d.ts +6 -0
  140. package/esm/tuple/tuple_plus.drop_match.d.ts.map +1 -0
  141. package/esm/tuple/tuple_plus.drop_match.js +2 -0
  142. package/esm/tuple/tuple_plus.drop_match.js.map +1 -0
  143. package/esm/tuple/tuple_plus.filter.d.ts +2 -2
  144. package/esm/tuple/tuple_plus.find.d.ts +64 -0
  145. package/esm/tuple/tuple_plus.find.d.ts.map +1 -0
  146. package/esm/tuple/tuple_plus.find.js +2 -0
  147. package/esm/tuple/tuple_plus.find.js.map +1 -0
  148. package/esm/tuple/tuple_plus.pad_start.d.ts +7 -6
  149. package/esm/tuple/tuple_plus.pad_start.d.ts.map +1 -1
  150. package/esm/tuple/tuple_type.d.ts +41 -23
  151. package/esm/tuple/tuple_type.d.ts.map +1 -1
  152. package/esm/union/union.d.ts +33 -0
  153. package/esm/union/union.d.ts.map +1 -0
  154. package/esm/union/union.js +2 -0
  155. package/esm/union/union.js.map +1 -0
  156. package/esm/unknown/unknown_type.d.ts +12 -0
  157. package/esm/unknown/unknown_type.d.ts.map +1 -1
  158. package/esm/utils/options.d.ts +10 -0
  159. package/esm/utils/options.d.ts.map +1 -0
  160. package/esm/utils/options.js +2 -0
  161. package/esm/utils/options.js.map +1 -0
  162. package/package.json +12 -1
  163. package/ts/array/array.entries.ts +4 -2
  164. package/ts/array/array_index.ts +33 -23
  165. package/ts/array/array_plus.common_prop_keys.ts +35 -0
  166. package/ts/array/array_plus.drop_match.ts +16 -0
  167. package/ts/array/array_plus.element_match.ts +61 -0
  168. package/ts/array/array_plus.find.ts +71 -0
  169. package/ts/array/array_plus.split_at.ts +52 -23
  170. package/ts/array/array_plus.ts +6 -3
  171. package/ts/array/find_first.ts +71 -0
  172. package/ts/array/head.ts +28 -6
  173. package/ts/array/last.ts +26 -6
  174. package/ts/array/readme.md +152 -32
  175. package/ts/assertion/assert_type.ts +4 -1
  176. package/ts/assertion/readme.md +3 -2
  177. package/ts/index.ts +5 -5
  178. package/ts/never/never_type.ts +13 -0
  179. package/ts/object/index.ts +0 -1
  180. package/ts/testing/test_type.ts +279 -277
  181. package/ts/tuple/common_prop_keys.ts +18 -32
  182. package/ts/tuple/drop.ts +61 -60
  183. package/ts/tuple/readme.md +178 -39
  184. package/ts/tuple/tuple_plus.common_prop_keys.ts +47 -0
  185. package/ts/tuple/tuple_plus.drop_match.ts +20 -0
  186. package/ts/tuple/tuple_plus.filter.ts +2 -2
  187. package/ts/tuple/tuple_plus.find.ts +88 -0
  188. package/ts/tuple/tuple_plus.pad_start.ts +28 -25
  189. package/ts/tuple/tuple_plus.ts +3 -0
  190. package/ts/tuple/tuple_type.ts +67 -25
  191. package/ts/union/readme.md +81 -0
  192. package/ts/union/union.ts +37 -0
  193. package/ts/unknown/unknown_type.ts +13 -0
  194. package/ts/utils/options.ts +10 -0
  195. package/cjs/array/array.find.d.ts +0 -23
  196. package/cjs/array/array.find.d.ts.map +0 -1
  197. package/cjs/array/array.find.js.map +0 -1
  198. package/esm/array/array.find.d.ts +0 -23
  199. package/esm/array/array.find.d.ts.map +0 -1
  200. package/esm/array/array.find.js +0 -2
  201. package/esm/array/array.find.js.map +0 -1
  202. package/ts/array/array.find.ts +0 -34
@@ -25,35 +25,45 @@ export type IndexAt<
25
25
  Fail = never,
26
26
  Upper = A['length'],
27
27
  Lower = 0
28
- > = IsEqual<
29
- A['length'],
30
- 0,
31
- Fail,
32
- Integer<
33
- N,
34
- StrictNumberType<
35
- A['length'],
36
- // A: array
37
- N,
38
- // A: tuple
39
- Negative<
40
- N,
41
- GreaterThan<Abs<N>, A['length']> extends true ? Lower : Subtract<A['length'], Abs<N>>,
42
- GreaterThan<A['length'], N> extends true ? N : Upper
43
- >
44
- >,
45
- // N: number or float
46
- IsAny<
28
+ > = IsNever<A, Fail, IndexAt._<A, N, Fail, Upper, Lower>>
29
+
30
+ export namespace IndexAt {
31
+ export type _<
32
+ A extends Array<unknown>,
33
+ N extends number,
34
+ Fail = never,
35
+ Upper = A['length'],
36
+ Lower = 0
37
+ > = IsEqual<
38
+ A['length'],
39
+ 0,
40
+ Fail,
41
+ Integer<
47
42
  N,
48
- number,
49
43
  StrictNumberType<
44
+ A['length'],
45
+ // A: array
46
+ N,
47
+ // A: tuple
48
+ Negative<
49
+ N,
50
+ GreaterThan<Abs<N>, A['length']> extends true ? Lower : Subtract<A['length'], Abs<N>>,
51
+ GreaterThan<A['length'], N> extends true ? N : Upper
52
+ >
53
+ >,
54
+ // N: number or float
55
+ IsAny<
50
56
  N,
51
- // TODO: handle tuple to union of indexes
52
- N
57
+ number,
58
+ StrictNumberType<
59
+ N,
60
+ // TODO: handle tuple to union of indexes
61
+ N
62
+ >
53
63
  >
54
64
  >
55
65
  >
56
- >
66
+ }
57
67
 
58
68
  /**
59
69
  * Is N an out of bound index of A.
@@ -0,0 +1,35 @@
1
+ import type { NeverType } from '../never/never_type.js'
2
+ import type { KeyTypes } from '../object/KeyTypes.js'
3
+
4
+ /**
5
+ * ⚗️ *transform*
6
+ * 🔢 *customization*
7
+ *
8
+ * Gets the common keys of the record types in the array `A`.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * import { type ArrayPlus } from 'type-plus'
13
+ *
14
+ * type R = ArrayPlus.CommonPropKeys<Array<{ a: 1 }>> // 'a'
15
+ * type R = ArrayPlus.CommonPropKeys<Array<{ a: 1, b: 1 } | { a: 1, c: 1 }>> // 'a'
16
+ * ```
17
+ *
18
+ * @typeParam Options['caseNever'] Return type when `T` is `never`.
19
+ * Default to `never`.
20
+ */
21
+ export type CommonPropKeys<
22
+ A extends Record<KeyTypes, unknown>[],
23
+ Options extends CommonPropKeys.Options = CommonPropKeys.DefaultOptions
24
+ > = NeverType<A,
25
+ Options['caseNever'],
26
+ A extends Array<infer R extends Record<KeyTypes, unknown>> ? keyof R : never
27
+ >
28
+
29
+ export namespace CommonPropKeys {
30
+ export interface Options extends NeverType.Options {
31
+ }
32
+
33
+ export interface DefaultOptions extends NeverType.DefaultOptions {
34
+ }
35
+ }
@@ -0,0 +1,16 @@
1
+ import type { NonNull } from '../utils/NonNull.js'
2
+ import type { NonUndefined } from '../utils/NonUndefined.js'
3
+
4
+ export type DropMatch<A extends Readonly<Array<unknown>>, Criteria> = A[0] extends Criteria
5
+ ? never[]
6
+ : (undefined extends Criteria
7
+ ? (null extends Criteria
8
+ ? Array<NonNullable<A[0]>>
9
+ : Array<NonUndefined<A[0]>>)
10
+ : (null extends Criteria
11
+ ? Array<NonNull<A[0]>>
12
+ : (Criteria extends A[0]
13
+ ? Array<Exclude<A[0], Criteria>>
14
+ : (A[0] extends Criteria
15
+ ? A
16
+ : Array<Exclude<A[0], Criteria>>))))
@@ -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,45 +1,74 @@
1
+ import type { NeverType } from '../never/never_type.js'
2
+ import type { IsTuple } from '../tuple/tuple_type.js'
1
3
  import type { IndexAt } from './array_index.js'
2
4
  import type { ArrayType } from './array_type.js'
3
5
 
4
6
  /**
5
- * Splits an array into two at the specified `Index`.
7
+ * ⚗️ *transform*
8
+ *
9
+ * Splits array or tuple `A` into two at the specified `Index`.
6
10
  *
7
11
  * If the `Index` is out of bounds,
8
- * it will set to the boundary value, similar to `array.splice()`.
12
+ * it will set to the boundary value.
13
+ *
14
+ * It is the type level `splice()`.
9
15
  *
10
16
  * @example
11
17
  * ```ts
12
- * SplitAt<[1, 2, 3, 4, 5], 0> // [[], [1, 2, 3, 4, 5]]
13
- * SplitAt<[1, 2, 3, 4, 5], -5> // [[], [1, 2, 3, 4, 5]]
14
- *
15
18
  * SplitAt<[1, 2, 3, 4, 5], 2> // [[1, 2], [3, 4, 5]]
19
+ * SplitAt<[1, 2, 3, 4, 5], -3> // [[1, 2], [3, 4, 5]]
16
20
  *
17
- * SplitAt<[1, 2, 3, 4, 5], 4> // [[1, 2, 3, 4], [5]]
18
- * SplitAt<[1, 2, 3, 4, 5], -1> // [[1, 2, 3, 4], [5]]
21
+ * SplitAt<[1, 2, 3, 4, 5], 2, 2> // [[1, 2, 5], [3, 4]]
19
22
  *
20
- * SplitAt<[1, 2, 3, 4, 5], 5> // [[1, 2, 3, 4, 5], []]
23
+ * SplitAt<[1, 2, 3, 4, 5], 2, 2, ['a', 'b']> // [[1, 2, 'a', 'b', 5], [3, 4]]
21
24
  *
22
25
  * // out of bound resets to boundary
23
26
  * SplitAt<[1, 2, 3, 4, 5], 6> // [[1, 2, 3, 4, 5], []]
24
27
  * SplitAt<[1, 2, 3, 4, 5], -6> // [[], [1, 2, 3, 4, 5]]
25
28
  * ```
26
29
  */
27
- export type SplitAt<A extends unknown[], Index extends number> = ArrayType<
30
+ export type SplitAt<
31
+ A extends unknown[],
32
+ Index extends number,
33
+ DeleteCount extends number | never = never,
34
+ Insert extends unknown[] | never = never
35
+ > = ArrayType<
28
36
  A,
29
37
  [A, A],
30
- ArraySplitAtDevice<A, [], IndexAt<A, Index>>
38
+ SplitAt._<A, [], [], IndexAt._<A, Index>, DeleteCount, Insert>
31
39
  >
32
40
 
33
- /**
34
- * Splits an array into two at the specified `Index`.
35
- * The device does not work on negative index nor out of bound index.
36
- */
37
- export type ArraySplitAtDevice<
38
- A extends unknown[],
39
- B extends unknown[],
40
- Index extends number
41
- > = Index extends B['length']
42
- ? [B, A]
43
- : A extends [infer Head, ...infer Tail]
44
- ? ArraySplitAtDevice<Tail, [...B, Head], Index>
45
- : never
41
+ export namespace SplitAt {
42
+ export type _<
43
+ A extends unknown[],
44
+ B extends unknown[],
45
+ C extends unknown[],
46
+ Index extends number,
47
+ DeleteCount,
48
+ Insert extends unknown[],
49
+ > = 0 extends A['length']
50
+ ? IsTuple<Insert, [[...Insert, ...B], C], [B, C]>
51
+ : (Index extends B['length']
52
+ ? _D<A, B, C, DeleteCount, Insert>
53
+ : (A extends [infer Head, ...infer Tail]
54
+ ? _<Tail, [...B, Head], [], Index, DeleteCount, Insert>
55
+ : 'unexpected: A does not extends [Head, ...Tail]'))
56
+
57
+ export type _D<
58
+ A extends unknown[],
59
+ B extends unknown[],
60
+ C extends unknown[],
61
+ DeleteCount,
62
+ Insert extends unknown[],
63
+ > = NeverType<
64
+ DeleteCount,
65
+ [B, A],
66
+ DeleteCount extends C['length']
67
+ ? IsTuple<Insert, [[...B, ...Insert, ...A], C], [[...B, ...A], C]>
68
+ : (A extends [infer Head, ...infer Tail]
69
+ ? _D<Tail, B, [...C, Head], DeleteCount, Insert>
70
+ : IsTuple<Insert, [[...Insert, ...B], C], [B, C]>
71
+ )
72
+ >
73
+ }
74
+
@@ -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
+ }