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
package/ts/tuple/drop.ts CHANGED
@@ -1,13 +1,14 @@
1
- import type { IsEqual } from '../equal/equal.js'
2
- import type { NonNull, NonUndefined } from '../utils/index.js'
1
+ import type { DropMatch as ArrayDropMatch } from '../array/array_plus.drop_match.js'
2
+ import type { DropMatch as TupleDropMatch } from './tuple_plus.drop_match.js'
3
3
 
4
4
  /**
5
+ * ⚗️ *transform*
6
+ * 🔢 *customizable*
7
+ *
5
8
  * Drops the first entry in the tuple `T`.
6
9
  *
7
10
  * If the type is an array, the same array will be returned.
8
11
  *
9
- * ⚗️ *transform*
10
- *
11
12
  * @example
12
13
  * ```ts
13
14
  * type R = DropFirst<[1, 2, 3]> // [2, 3]
@@ -15,30 +16,45 @@ import type { NonNull, NonUndefined } from '../utils/index.js'
15
16
  * type R = DropFirst<[]> // []
16
17
  * type R = DropFirst<string[]> // string[]
17
18
  * ```
19
+ *
20
+ * @typeParam Options['caseArray'] Return type when `T` is `Array`.
21
+ * Default to `T`.
22
+ *
23
+ * @typeParam Options['caseEmptyTuple'] Return type when `T` is an empty tuple.
24
+ * Default to `[]`.
18
25
  */
19
- export type DropFirst<T extends unknown[], Cases extends {
20
- 'array'?: unknown,
21
- 'empty_tuple'?: unknown,
22
- } = {
23
- 'array': T,
24
- 'empty_tuple': [],
25
- }> = number extends T['length']
26
- ? Cases['array']
26
+ export type DropFirst<
27
+ T extends unknown[],
28
+ Options extends DropFirst.Options = DropFirst.DefaultOptions<T>
29
+ > = number extends T['length']
30
+ ? Options['caseArray']
27
31
  : T['length'] extends 0
28
- ? Cases['empty_tuple']
32
+ ? Options['caseEmptyTuple']
29
33
  : T['length'] extends 1
30
34
  ? []
31
35
  : T extends [any, ...infer Tail]
32
36
  ? Tail
33
37
  : never
34
38
 
39
+ export namespace DropFirst {
40
+ export interface Options {
41
+ caseArray?: unknown,
42
+ caseEmptyTuple?: unknown,
43
+ }
44
+ export interface DefaultOptions<T> {
45
+ caseArray: T,
46
+ caseEmptyTuple: []
47
+ }
48
+ }
49
+
35
50
  /**
51
+ * ⚗️ *transform*
52
+ * 🔢 *customizable*
53
+ *
36
54
  * Drops the last entry in the tuple `T`.
37
55
  *
38
56
  * If the type is an array, the same array will be returned.
39
57
  *
40
- * ⚗️ *transform*
41
- *
42
58
  * @example
43
59
  * ```ts
44
60
  * type R = DropLast<[1, 2, 3]> // [2, 3]
@@ -46,30 +62,44 @@ export type DropFirst<T extends unknown[], Cases extends {
46
62
  * type R = DropLast<[]> // []
47
63
  * type R = DropLast<string[]> // string[]
48
64
  * ```
65
+ *
66
+ * @typeParam Options['caseArray'] Return type when `T` is `Array`.
67
+ * Default to `T`.
68
+ *
69
+ * @typeParam Options['caseEmptyTuple'] Return type when `T` is an empty tuple.
70
+ * Default to `[]`.
49
71
  */
50
- export type DropLast<T extends unknown[], Cases extends {
51
- 'array'?: unknown,
52
- 'empty_tuple'?: unknown,
53
- } = {
54
- 'array': T,
55
- 'empty_tuple': [],
56
- }> = number extends T['length']
57
- ? Cases['array']
72
+ export type DropLast<
73
+ T extends unknown[],
74
+ Cases extends DropLast.Options = DropLast.DefaultOptions<T>
75
+ > = number extends T['length']
76
+ ? Cases['caseArray']
58
77
  : T['length'] extends 0
59
- ? Cases['empty_tuple']
78
+ ? Cases['caseEmptyTuple']
60
79
  : T['length'] extends 1
61
80
  ? []
62
81
  : T extends [...infer Heads, any]
63
82
  ? Heads
64
83
  : never
65
84
 
66
- type ExcludeUnionOfEmptyTuple<A> = IsEqual<A, []> extends true ? A : Exclude<A, []>
85
+
86
+ export namespace DropLast {
87
+ export interface Options {
88
+ caseArray?: unknown,
89
+ caseEmptyTuple?: unknown,
90
+ }
91
+ export interface DefaultOptions<T> {
92
+ caseArray: T,
93
+ caseEmptyTuple: []
94
+ }
95
+ }
96
+
67
97
 
68
98
  /**
69
- * drops entries matching `Criteria` in array or tuple `A`.
70
- *
71
99
  * ⚗️ *transform*
72
100
  *
101
+ * Drops entries matching `Criteria` in array or tuple `A`.
102
+ *
73
103
  * @example
74
104
  * ```ts
75
105
  * type R = DropMatch<Array<string | undefined>, undefined> // string[]
@@ -77,38 +107,9 @@ type ExcludeUnionOfEmptyTuple<A> = IsEqual<A, []> extends true ? A : Exclude<A,
77
107
  * type R = DropMatch<Array<1 | 2>, number> // never[]
78
108
  * ```
79
109
  */
80
- export type DropMatch<A extends Readonly<Array<unknown>>, Criteria> = number extends A['length']
81
- ? // array
82
- A[0] extends Criteria
83
- ? // criteria matches: DropAll<string[], string>
84
- never[]
85
- : undefined extends Criteria
86
- ? null extends Criteria
87
- ? Array<NonNullable<A[0]>>
88
- : Array<NonUndefined<A[0]>>
89
- : null extends Criteria
90
- ? Array<NonNull<A[0]>>
91
- : Criteria extends A[0]
92
- ? Array<Exclude<A[0], Criteria>>
93
- : A[0] extends Criteria
94
- ? A
95
- : Array<Exclude<A[0], Criteria>>
96
- : DropMatchTuple<A, Criteria>
97
-
98
- type DropMatchTuple<A extends Readonly<Array<any>>, Criteria> = A['length'] extends 0
99
- ? // empty tuple
100
- A
101
- : A extends readonly [infer Head, ...infer Tail]
102
- ? Tail['length'] extends 0
103
- ? // single element tuple
104
- undefined extends Criteria
105
- ? ExcludeUnionOfEmptyTuple<Head extends Criteria ? [] : [Head]>
106
- : ExcludeUnionOfEmptyTuple<Head extends Criteria ? [] : [Head]>
107
- : // multiple elements
108
- Exclude<Head, Criteria> extends never
109
- ? DropMatch<Tail, Criteria>
110
- : [Exclude<Head, Criteria>, ...DropMatch<Tail, Criteria>]
111
- : never[]
110
+ export type DropMatch<A extends Readonly<Array<unknown>>, Criteria> = number extends A['length']
111
+ ? ArrayDropMatch<A, Criteria>
112
+ : TupleDropMatch<A, Criteria>
112
113
 
113
114
  export type DropNull<A extends Array<any>> = DropMatch<A, null>
114
115
  export type DropNullable<A extends Array<any>> = DropMatch<A, null | undefined>
@@ -119,6 +120,6 @@ export type DropUndefined<A extends Array<any>> = DropMatch<A, undefined>
119
120
  *
120
121
  * 💀 *deprecated* the type does not sufficiently cover the use cases.
121
122
  */
122
- export function drop<A extends Readonly<unknown[]>, const C> (array: A, value: C): DropMatch < A, C > {
123
+ export function drop<A extends Readonly<unknown[]>, const C>(array: A, value: C): DropMatch<A, C> {
123
124
  return array.filter(v => v !== value) as DropMatch<A, C>
124
125
  }
@@ -9,87 +9,175 @@ Each entry in the *tuple* is specified explicitly.
9
9
 
10
10
  The `TupleType<T>` and friends are used to check if `T` is a tuple, excluding array.
11
11
 
12
+ ### [TupleType](./tuple_type.ts#l21)
13
+
14
+ `TupleType<T, Then = T, Else = never, Cases = { never }>`
15
+
16
+ 🌪️ *filter*
17
+
18
+ Filter `T` to ensure it is a tuple, excluding array.
19
+
12
20
  ```ts
13
21
  import type { TupleType } from 'type-plus'
14
22
 
15
- type R = TupleType<[]> // []
16
- type R = TupleType<[1]> // [1]
23
+ type R = TupleType<[]> // []
24
+ type R = TupleType<[1]> // [1]
17
25
 
18
- type R = TupleType<number[]> // never
19
- type R = TupleType<number> // never
26
+ type R = TupleType<number[]> // never
27
+ type R = TupleType<string> // never
28
+ type R = TupleType<never> // never
29
+ type R = TupleType<unknown> // never
20
30
  ```
21
31
 
22
- - [`TupleType<T, Then = T, Else = never>`](tuple_type.ts#L16): check if `T` is a *tuple*.
23
- - [`IsTuple<T, Then = true, Else = false`](tuple_type.ts#L35): is `T` *tuple*.
24
- - [`NotTupleType<T, Then = T, Else = never>`](tuple_type.ts#L50): check if `T` is not *tuple*.
25
- - [`IsNotTuple<T, Then = true, Else = false>`](tuple_type.ts#L65): is `T` not *tuple*.
32
+ Overridable cases:
26
33
 
27
- ## [CommonPropKeys](./common_prop_keys.ts)
34
+ - `never`: if `T` is `never`, it returns `Else`.
28
35
 
29
- `CommonPropKeys<T extends Record[], Cases = { array, no_common_keys }>`
36
+ ### [IsTuple](./array_type.ts#l47)
30
37
 
31
- ⚗️ *transform*
38
+ `IsTuple<T, Then = true, Else = false, Cases = { never }>`
32
39
 
33
- Gets the common property keys of the elements in tuple `T`.
40
+ 🎭 *validate*
41
+
42
+ Validate that `T` is a tuple, excluding array.
34
43
 
35
44
  ```ts
36
- import { CommonPropKeys } from 'type-plus'
45
+ import type { IsTuple } from 'type-plus'
37
46
 
38
- type R = CommonPropKeys<[{ a: number }, { b: number }]> // never
39
- type R = CommonPropKeys<[{ a: number, c: 1 }, { b: number, c: 2 }]> // 'c'
47
+ type R = IsTuple<[]> // true
48
+
49
+ type R = IsTuple<number[]> // false
50
+ type R = IsTuple<string> // false
51
+ type R = IsTuple<never> // false
52
+ type R = IsTuple<unknown> // false
40
53
  ```
41
54
 
42
55
  Overridable cases:
43
56
 
44
- - `array`: if `T` is array, it returns the key of the record type in the array.
45
- - `no_common_keys`: if there are no common keys, it returns `never`.
57
+ - `never`: if `T` is `never`, it returns `Else`.
46
58
 
47
- ## [DropFirst](./drop.ts)
59
+ ### [NotTupleType](./tuple_type.ts#l70)
48
60
 
49
- `DropFirst<T extends unknown[], Cases = { array, empty_tuple }>`
61
+ `NotArrayType<T, Then = T, Else = never, Cases = { never }>`
50
62
 
51
- Drops the first entry in the tuple `T`.
63
+ 🌪️ *filter*
52
64
 
53
- ⚗️ *transform*
65
+ Filter `T` to ensure it is not an tuple, excluding array.
54
66
 
55
67
  ```ts
56
- import { DropFirst } from 'type-plus'
68
+ import type { NotArrayType } from 'type-plus'
57
69
 
58
- type R = DropFirst<[1, 2, 3]> // [2, 3]
70
+ type R = NotTupleType<[]> // never
71
+ type R = NotTupleType<[1]> // never
72
+
73
+ type R = NotTupleType<number[]> // number[]
74
+ type R = NotTupleType<string> // string
75
+ type R = NotTupleType<never> // never
76
+ type R = NotTupleType<unknown> // unknown
59
77
  ```
60
78
 
61
79
  Overridable cases:
62
80
 
63
- - `array`: if `T` is array, it returns `T`.
64
- - `empty_tuple`: if `T` is `[]`, it returns `[]`.
81
+ - `never`: if `T` is `never`, it returns `Else`.
65
82
 
66
- ## [DropLast](./drop.ts)
83
+ ### [IsNotTupleType](./tuple_type.ts#l92)
67
84
 
68
- `DropLast<T extends unknown[], Cases = { array, empty_tuple }>`
85
+ `IsNotTupleType<T, Then = true, Else = false, Cases = { never }>`
69
86
 
70
- Drops the last entry in the tuple `T`.
87
+ 🎭 *validate*
71
88
 
72
- ⚗️ *transform*
89
+ Validate that `T` is not a tuple, excluding array.
73
90
 
74
91
  ```ts
75
- import { DropLast } from 'type-plus'
92
+ import type { IsNotTupleType } from 'type-plus'
93
+
94
+ type R = IsNotTuple<[]> // false
95
+ type R = IsNotTuple<[1]> // false
76
96
 
77
- type R = DropLast<[1, 2, 3]> // [1, 2]
97
+ type R = IsNotTuple<number[]> // true
98
+ type R = IsNotTuple<string> // true
99
+ type R = IsNotTuple<never> // true
100
+ type R = IsNotTuple<unknown> // true
78
101
  ```
79
102
 
80
103
  Overridable cases:
81
104
 
82
- - `array`: if `T` is array, it returns `T`.
83
- - `empty_tuple`: if `T` is `[]`, it returns `[]`.
105
+ - `never`: if `T` is `never`, it returns `Else`.
106
+
107
+ ## [CommonPropKeys](./common_prop_keys.ts#l22)
108
+
109
+ `CommonPropKeys<T extends Record[], Options = { caseNever }>`
110
+
111
+ ⚗️ *transform*
112
+ 🔢 *customizable*
113
+
114
+ Gets the common property keys of the elements in tuple or array `T`.
115
+
116
+ ```ts
117
+ import { CommonPropKeys } from 'type-plus'
118
+
119
+ type R = CommonPropKeys<[{ a: 1, c: 1 }, { b: 1, c: 2 }]> // 'c'
120
+ type R = CommonPropKeys<[{ a: 1 }, { b: 1 }]> // never
121
+ type R = CommonPropKeys<Array<{ a: 1, b: 1 } | { a: 1, c: 1 }>> // 'a'
122
+ type R = CommonPropKeys<[{ a: 1 }, { b: 1 }]> // never
123
+ type R = CommonPropKeys<never> // caseNever: never
124
+
125
+ // customization
126
+ type R = CommonPropKeys<never, { caseNever: 1 }> // 1
127
+ ```
128
+
129
+ ## [DropFirst](./drop.ts#l26)
130
+
131
+ `DropFirst<T extends unknown[], Options = { caseArray, caseEmptyTuple }>`
132
+
133
+ ⚗️ *transform*
134
+ 🔢 *customizable*
135
+
136
+ Drops the first entry in the tuple `T`.
137
+
138
+ ```ts
139
+ import { DropFirst } from 'type-plus'
140
+
141
+ type R = DropFirst<[1, 2, 3]> // [2, 3]
142
+ type R = DropFirst<[string]> // []
143
+ type R = DropFirst<string[]> // caseArray: string[]
144
+ type R = DropFirst<[]> // caseEmptyTuple: []
145
+
146
+ // customization
147
+ type R = DropFirst<string[], { caseArray: 1 }> // 1
148
+ type R = DropFirst<[], { caseEmptyTuple: 1 }> // 1
149
+ ```
150
+
151
+ ## [DropLast](./drop.ts#l72)
152
+
153
+ `DropLast<T extends unknown[], Options = { array, empty_tuple }>`
154
+
155
+ ⚗️ *transform*
156
+ 🔢 *customizable*
157
+
158
+ Drops the last entry in the tuple `T`.
159
+
160
+ ```ts
161
+ import { DropLast } from 'type-plus'
162
+
163
+ type R = DropLast<[1, 2, 3]> // [2, 3]
164
+ type R = DropLast<[string]> // []
165
+ type R = DropLast<string[]> // caseArray: string[]
166
+ type R = DropLast<[]> // caseEmptyTuple: []
167
+
168
+ // customization
169
+ type R = DropLast<string[], { caseArray: 1 }> // 1
170
+ type R = DropLast<[], { caseEmptyTuple: 1 }> // 1
171
+ ```
84
172
 
85
173
  ## [DropMatch](./drop.ts)
86
174
 
87
175
  `DropMatch<A extends Readonly<Array<unknown>>, Criteria>`
88
176
 
89
- Drops entries matching `Criteria` in array or tuple `A`.
90
-
91
177
  ⚗️ *transform*
92
178
 
179
+ Drops entries matching `Criteria` in array or tuple `A`.
180
+
93
181
  ```ts
94
182
  type R = DropMatch<Array<string | undefined>, undefined> // string[]
95
183
  type R = DropMatch<Array<string>, string> // never[]
@@ -101,31 +189,82 @@ type R = DropMatch<Array<1 | 2>, number> // never[]
101
189
  `TuplePlus` contains type utilities specific for *tuple*.
102
190
  The input type are not checked and assumed to be *tuple*.
103
191
 
192
+ ## [TuplePlus.CommonPropKeys](./tuple_plus.common_prop_keys.ts#l22)
193
+
194
+ `TuplePlus.CommonPropKeys<T extends Record[], Options = { caseNever }>`
195
+
196
+ ⚗️ *transform*
197
+ 🔢 *customizable*
198
+
199
+ Gets the common property keys of the elements in tuple `T`.
200
+
201
+ ```ts
202
+ import { type TuplePlus } from 'type-plus'
203
+
204
+ type R = TuplePlus.CommonPropKeys<[{ a: 1, c: 1 }, { b: 1, c: 2 }]> // 'c'
205
+ type R = TuplePlus.CommonPropKeys<[{ a: 1 }, { b: 1 }]> // never
206
+ type R = TuplePlus.CommonPropKeys<Array<{ a: 1, b: 1 } | { a: 1, c: 1 }>> // 'a'
207
+ type R = TuplePlus.CommonPropKeys<[{ a: 1 }, { b: 1 }]> // never
208
+ type R = TuplePlus.CommonPropKeys<never> // caseNever: never
209
+
210
+ // customization
211
+ type R = TuplePlus.CommonPropKeys<never, { caseNever: 1 }> // 1
212
+ ```
213
+
104
214
  ### [TuplePlus.Filter](./tuple_plus.filter.ts)
105
215
 
106
216
  `TuplePlus.Filter<T, Criteria>`
107
217
 
108
- Filter entries matching `Criteria` in tuple `T`.
109
-
110
218
  ⚗️ *transform*
111
219
 
220
+ Filter entries matching `Criteria` in tuple `T`.
221
+
112
222
  ```ts
113
223
  import { TuplePlus } from 'type-plus'
114
224
 
115
225
  type R = TuplePlus.Filter<[1, 2, '3'], number> // [1, 2]
116
226
  ```
117
227
 
228
+ ### [`TuplePlus.Find`](./tuple_plus.find.ts#l51)
229
+
230
+ `TuplePlus.Find<A, Criteria, Options { widen, caseArray, caseEmptyTuple, caseNever, caseNotMatch, caseWiden, caseUnionNotMatch }>`
231
+
232
+ 🦴 *utilities*
233
+ 🔢 *customizable*
234
+
235
+ Finds the type in tuple `A` that matches `Criteria`.
236
+
237
+ ```ts
238
+ import type { TuplePlus } from 'type-plus'
239
+
240
+ type R = TuplePlus.Find<[true, 1, 'x', 3], string> // 'x'
241
+ type R = TuplePlus.Find<[true, 1, 'x', 3], number> // 1
242
+ type R = TuplePlus.Find<[string, number, 1], 1> // widen: 1 | undefined
243
+ type R = TuplePlus.Find<[true, number | string], string> // unionNotMatch: string
244
+
245
+ type R = TuplePlus.Find<[true, 1, 'x'], 2> // never
246
+
247
+ // customization
248
+ type R = TuplePlus.Find<[number], 1, { widen: false }> // never
249
+ type R = TuplePlus.Find<[number], 1, { caseWiden: never }> // never
250
+ type R = TuplePlus.Find<string[], 1, { caseArray: 2 }> // 2
251
+ type R = TuplePlus.Find<[], 1, { caseEmptyTuple: 2 }> // 2
252
+ type R = TuplePlus.Find<never, 1, { caseNever: 2 }> // 2
253
+ type R = TuplePlus.Find<[string], number, { caseNotMatch: 2 }> // 2
254
+ type R = TuplePlus.Find<[string | number], number, { caseUnionNotMatch: undefined }> // number | undefined
255
+ ```
256
+
118
257
  ### [TuplePlus.PadStart](./tuple_plus.pad_start.ts)
119
258
 
120
259
  `TuplePlus.PadStart<T, MaxLength, PadWith>`
121
260
 
261
+ ⚗️ *transform*
262
+
122
263
  Pad `T` with `PadWith` at the start of the tuple.
123
264
 
124
265
  If the `MaxLength` is less than the length of the tuple,
125
266
  the `Tuple` will be returned unchanged.
126
267
 
127
- ⚗️ *transform*
128
-
129
268
  ```ts
130
269
  PadStart<[1, 2, 3], 5, 0> // [0, 0, 1, 2, 3]
131
270
 
@@ -0,0 +1,47 @@
1
+ import type { NeverType } from '../never/never_type.js'
2
+ import type { KeyTypes } from '../object/KeyTypes.js'
3
+ import type { Tail } from './tail.js'
4
+
5
+ /**
6
+ * ⚗️ *transform*
7
+ * 🔢 *customization*
8
+ *
9
+ * Gets the common property keys of the elements in tuple `T`.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { type TuplePlus } from 'type-plus'
14
+ *
15
+ * type R = TuplePlus.CommonPropKeys<[{ a: number }, { b: number }]> // never
16
+ * type R = TuplePlus.CommonPropKeys<[{ a: number, c: 1 }, { b: number, c: 2 }]> // 'c'
17
+ * ```
18
+ *
19
+ * @typeParam Options['caseNever'] Return type when `T` is `never`.
20
+ * Default to `never`.
21
+ */
22
+ export type CommonPropKeys<
23
+ T extends Record<KeyTypes, unknown>[],
24
+ Options extends CommonPropKeys.Options = CommonPropKeys.DefaultOptions
25
+ > = NeverType<
26
+ T,
27
+ Options['caseNever'],
28
+ (T['length'] extends 0
29
+ ? never
30
+ : (
31
+ T['length'] extends 1
32
+ ? keyof T[0]
33
+ : (
34
+ T['length'] extends 2
35
+ ? keyof T[0] & keyof T[1]
36
+ : keyof T[0] & keyof T[1] & CommonPropKeys<Tail<Tail<T>>>
37
+ )
38
+ ))
39
+ >
40
+
41
+ export namespace CommonPropKeys {
42
+ export interface Options extends NeverType.Options {
43
+ }
44
+
45
+ export interface DefaultOptions extends NeverType.DefaultOptions {
46
+ }
47
+ }
@@ -0,0 +1,20 @@
1
+ import type { IsEqual } from '../equal/equal.js'
2
+
3
+ export type DropMatch<A extends Readonly<Array<unknown>>, Criteria> = A['length'] extends 0
4
+ ? // empty tuple
5
+ A
6
+ : A extends readonly [infer Head, ...infer Tail]
7
+ ? Tail['length'] extends 0
8
+ ? // single element tuple
9
+ undefined extends Criteria
10
+ ? DropMatch.ExcludeUnionOfEmptyTuple<Head extends Criteria ? [] : [Head]>
11
+ : DropMatch.ExcludeUnionOfEmptyTuple<Head extends Criteria ? [] : [Head]>
12
+ : // multiple elements
13
+ Exclude<Head, Criteria> extends never
14
+ ? DropMatch<Tail, Criteria>
15
+ : [Exclude<Head, Criteria>, ...DropMatch<Tail, Criteria>]
16
+ : never[]
17
+
18
+ export namespace DropMatch {
19
+ export type ExcludeUnionOfEmptyTuple<A> = IsEqual<A, []> extends true ? A : Exclude<A, []>
20
+ }
@@ -1,8 +1,8 @@
1
1
  /**
2
- * Filter entries matching `Criteria` in tuple `T`.
3
- *
4
2
  * ⚗️ *transform*
5
3
  *
4
+ * Filter entries matching `Criteria` in tuple `T`.
5
+ *
6
6
  * @example
7
7
  * ```ts
8
8
  * type R = Filter<[1, 2, '3'], number> // [1, 2]
@@ -0,0 +1,88 @@
1
+ import type { ElementMatch } from '../array/array_plus.element_match.js'
2
+ import type { NeverType } from '../never/never_type.js'
3
+ import type { MergeOptions } from '../utils/options.js'
4
+ import type { TupleType } from './tuple_type.js'
5
+
6
+ /**
7
+ * 🦴 *utilities*
8
+ * 🔢 *customizable*
9
+ *
10
+ * Find the first type in tuple `A` that matches `Criteria`.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * type R = TuplePlus.Find<[true, 1, 'x', 3], string> // 'x'
15
+ * type R = TuplePlus.Find<[true, 1, 'x', 3], number> // 1
16
+ * type R = TuplePlus.Find<[string, number, 1], 1> // widen: 1 | undefined
17
+ * type R = TuplePlus.Find<[true, number | string], string> // unionMiss: string | undefined
18
+ *
19
+ * type R = TuplePlus.Find<[true, 1, 'x'], 2> // never
20
+ * ```
21
+ *
22
+ * @typeParam Options['widen'] performs widen match.
23
+ * Default to `true`.
24
+ * With widen match, a narrowed type will match its widen type.
25
+ * e.g. matching `1` against `number` yields `1 | undefined`
26
+ *
27
+ * The widen behavior can be customized by `Options['caseWiden']`
28
+ *
29
+ * @typeParam Options['caseArray'] return type when `A` is an array. Default to `not supported` message.
30
+ *
31
+ * @typeParam Options['caseEmptyTuple'] return type when `A` is an empty tuple.
32
+ * Default to `never`.
33
+ *
34
+ * @typeParam Options['caseNever'] return type when `A` is `never`. Default to `never`.
35
+ *
36
+ * @typeParam Options['caseNotMatch'] Return value when `T` does not match `Criteria`.
37
+ * Default to `never`.
38
+ *
39
+ * @typeParam Options['caseWiden'] return type when `T` in `A` is a widen type of `Criteria`.
40
+ * Default to `Criteria | undefined`.
41
+ * Set it to `never` for a more type-centric behavior
42
+ *
43
+ * @typeParam Options['caseUnionNotMatch'] Return value when a branch of the union `T` does not match `Criteria`.
44
+ * Default to `never`.
45
+ *
46
+ * If you want the type to behave more like JavaScript,
47
+ * you can override it to return `undefined`.
48
+ *
49
+ * Since it is a union, the result will be joined to the matched branch as union.
50
+ */
51
+ export type Find<
52
+ A extends unknown[],
53
+ Criteria,
54
+ Options extends Find.Options = Find.DefaultOptions<Criteria>
55
+ > = MergeOptions<Options, Find.DefaultOptions<Criteria>> extends infer O extends Find.Options
56
+ ? TupleType<
57
+ A,
58
+ A['length'] extends 0
59
+ ? O['caseEmptyTuple']
60
+ : Find.Device<A, Criteria, O>,
61
+ O['caseArray'],
62
+ O
63
+ >
64
+ : never
65
+ export namespace Find {
66
+ export type Device<
67
+ A extends unknown[],
68
+ Criteria,
69
+ Options extends Find.Options
70
+ > = A['length'] extends 0
71
+ ? Options['caseNotMatch']
72
+ : (A extends [infer Head, ...infer Tail]
73
+ ? ElementMatch<
74
+ Head,
75
+ Criteria,
76
+ MergeOptions<{ caseNotMatch: Device<Tail, Criteria, Options> }, Options>
77
+ >
78
+ : never)
79
+ export interface Options extends ElementMatch.Options, NeverType.Options {
80
+ caseArray?: unknown,
81
+ caseEmptyTuple?: unknown,
82
+ }
83
+
84
+ export interface DefaultOptions<Criteria> extends ElementMatch.DefaultOptions<Criteria>, NeverType.DefaultOptions {
85
+ caseArray: 'does not support array. Please use `FindFirst` or `ArrayPlus.Find` instead.',
86
+ caseEmptyTuple: never,
87
+ }
88
+ }