ts-data-forge 13.0.0 → 14.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -3
- package/dist/array/impl/array-utils-creation.d.mts +2 -2
- package/dist/array/impl/array-utils-creation.d.mts.map +1 -1
- package/dist/array/impl/array-utils-creation.mjs.map +1 -1
- package/dist/array/impl/array-utils-length-bounded-array-cast.d.mts +56 -29
- package/dist/array/impl/array-utils-length-bounded-array-cast.d.mts.map +1 -1
- package/dist/array/impl/array-utils-length-bounded-array-cast.mjs +23 -15
- package/dist/array/impl/array-utils-length-bounded-array-cast.mjs.map +1 -1
- package/dist/array/impl/array-utils-length-bounded-array-guard.d.mts +126 -28
- package/dist/array/impl/array-utils-length-bounded-array-guard.d.mts.map +1 -1
- package/dist/array/impl/array-utils-length-bounded-array-guard.mjs +39 -5
- package/dist/array/impl/array-utils-length-bounded-array-guard.mjs.map +1 -1
- package/dist/array/impl/array-utils-length-bounded-tuple-cast.d.mts +167 -0
- package/dist/array/impl/array-utils-length-bounded-tuple-cast.d.mts.map +1 -0
- package/dist/array/impl/array-utils-length-bounded-tuple-cast.mjs +87 -0
- package/dist/array/impl/array-utils-length-bounded-tuple-cast.mjs.map +1 -0
- package/dist/array/impl/array-utils-length-bounded-tuple-guard.d.mts +135 -0
- package/dist/array/impl/array-utils-length-bounded-tuple-guard.d.mts.map +1 -0
- package/dist/array/impl/array-utils-length-bounded-tuple-guard.mjs +41 -0
- package/dist/array/impl/array-utils-length-bounded-tuple-guard.mjs.map +1 -0
- package/dist/array/impl/array-utils-modification.d.mts +45 -18
- package/dist/array/impl/array-utils-modification.d.mts.map +1 -1
- package/dist/array/impl/array-utils-modification.mjs.map +1 -1
- package/dist/array/impl/array-utils-reducing-value.d.mts +3 -3
- package/dist/array/impl/array-utils-reducing-value.d.mts.map +1 -1
- package/dist/array/impl/array-utils-reducing-value.mjs +1 -1
- package/dist/array/impl/array-utils-reducing-value.mjs.map +1 -1
- package/dist/array/impl/array-utils-slice-clamped.d.mts.map +1 -1
- package/dist/array/impl/array-utils-slice-clamped.mjs.map +1 -1
- package/dist/array/impl/array-utils-slicing.d.mts +11 -11
- package/dist/array/impl/array-utils-slicing.d.mts.map +1 -1
- package/dist/array/impl/array-utils-slicing.mjs +1 -1
- package/dist/array/impl/array-utils-slicing.mjs.map +1 -1
- package/dist/array/impl/array-utils-transformation.d.mts +36 -19
- package/dist/array/impl/array-utils-transformation.d.mts.map +1 -1
- package/dist/array/impl/array-utils-transformation.mjs +2 -2
- package/dist/array/impl/array-utils-transformation.mjs.map +1 -1
- package/dist/array/impl/array-utils-validation.d.mts +2 -124
- package/dist/array/impl/array-utils-validation.d.mts.map +1 -1
- package/dist/array/impl/array-utils-validation.mjs +1 -7
- package/dist/array/impl/array-utils-validation.mjs.map +1 -1
- package/dist/array/impl/index.d.mts +2 -0
- package/dist/array/impl/index.d.mts.map +1 -1
- package/dist/array/impl/index.mjs +5 -3
- package/dist/array/impl/index.mjs.map +1 -1
- package/dist/collections/imap.d.mts +1 -1
- package/dist/collections/imap.mjs.map +1 -1
- package/dist/collections/iset-mapped.d.mts +2 -2
- package/dist/collections/iset-mapped.d.mts.map +1 -1
- package/dist/collections/iset-mapped.mjs.map +1 -1
- package/dist/collections/iset.d.mts +2 -2
- package/dist/collections/iset.d.mts.map +1 -1
- package/dist/collections/iset.mjs.map +1 -1
- package/dist/number/num-arithmetic-types.d.mts +2 -2
- package/dist/number/num-arithmetic-types.d.mts.map +1 -1
- package/dist/object/object.mjs +1 -1
- package/dist/string/str.d.mts +44 -44
- package/dist/string/str.d.mts.map +1 -1
- package/dist/string/str.mjs +17 -17
- package/dist/string/str.mjs.map +1 -1
- package/package.json +4 -5
- package/src/array/impl/array-utils-creation.mts +7 -3
- package/src/array/impl/array-utils-creation.test.mts +10 -8
- package/src/array/impl/array-utils-length-bounded-array-cast.mts +88 -50
- package/src/array/impl/array-utils-length-bounded-array-cast.test.mts +40 -13
- package/src/array/impl/array-utils-length-bounded-array-guard.mts +248 -39
- package/src/array/impl/array-utils-length-bounded-array-guard.test.mts +135 -24
- package/src/array/impl/array-utils-length-bounded-tuple-cast.mts +364 -0
- package/src/array/impl/array-utils-length-bounded-tuple-cast.test.mts +207 -0
- package/src/array/impl/array-utils-length-bounded-tuple-guard.mts +266 -0
- package/src/array/impl/array-utils-length-bounded-tuple-guard.test.mts +441 -0
- package/src/array/impl/array-utils-length-constraint-preservation.test.mts +287 -0
- package/src/array/impl/array-utils-modification.mts +84 -61
- package/src/array/impl/array-utils-modification.test.mts +145 -6
- package/src/array/impl/array-utils-reducing-value.mts +5 -5
- package/src/array/impl/array-utils-shape-invariants.test.mts +284 -0
- package/src/array/impl/array-utils-slice-clamped.mts +2 -1
- package/src/array/impl/array-utils-slicing.mts +65 -43
- package/src/array/impl/array-utils-slicing.test.mts +55 -0
- package/src/array/impl/array-utils-transformation.mts +91 -37
- package/src/array/impl/array-utils-transformation.test.mts +96 -23
- package/src/array/impl/array-utils-validation.mts +2 -162
- package/src/array/impl/array-utils-validation.test.mts +0 -371
- package/src/array/impl/index.mts +2 -0
- package/src/collections/imap.mts +1 -1
- package/src/collections/iset-mapped.mts +7 -3
- package/src/collections/iset.mts +7 -3
- package/src/collections/iset.test.mts +9 -6
- package/src/collections/queue.test.mts +1 -1
- package/src/number/num-arithmetic-types.mts +8 -4
- package/src/number/num.test.mts +2 -2
- package/src/string/str.mts +69 -69
- package/src/string/str.test.mts +40 -40
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
|
+
type ConstrainedList,
|
|
3
|
+
type HasLengthConstraint,
|
|
2
4
|
type List,
|
|
3
5
|
type NonEmptyArray,
|
|
4
6
|
type NonEmptyTuple,
|
|
@@ -6,9 +8,9 @@ import {
|
|
|
6
8
|
} from 'ts-type-forge';
|
|
7
9
|
import { Uint32 } from '../../number/index.mjs';
|
|
8
10
|
import { type SizeType } from '../../types.mjs';
|
|
11
|
+
import { isEmpty } from './array-utils-length-bounded-array-guard.mjs';
|
|
9
12
|
import { size } from './array-utils-size.mjs';
|
|
10
13
|
import { sliceClamped } from './array-utils-slice-clamped.mjs';
|
|
11
|
-
import { isEmpty } from './array-utils-validation.mjs';
|
|
12
14
|
|
|
13
15
|
/**
|
|
14
16
|
* Returns all elements of an array except the first one.
|
|
@@ -41,9 +43,9 @@ import { isEmpty } from './array-utils-validation.mjs';
|
|
|
41
43
|
*/
|
|
42
44
|
export const tail = <const Ar extends readonly unknown[]>(
|
|
43
45
|
array: Ar,
|
|
44
|
-
):
|
|
46
|
+
): ConstrainedList.Tail<Ar> =>
|
|
45
47
|
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
46
|
-
array.slice(1) as unknown as
|
|
48
|
+
array.slice(1) as unknown as ConstrainedList.Tail<Ar>;
|
|
47
49
|
|
|
48
50
|
/**
|
|
49
51
|
* Returns all elements of an array except the last one.
|
|
@@ -62,9 +64,11 @@ export const tail = <const Ar extends readonly unknown[]>(
|
|
|
62
64
|
*/
|
|
63
65
|
export const butLast = <const Ar extends readonly unknown[]>(
|
|
64
66
|
array: Ar,
|
|
65
|
-
):
|
|
67
|
+
): ConstrainedList.ButLast<Ar> =>
|
|
66
68
|
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
67
|
-
(isEmpty(array)
|
|
69
|
+
(isEmpty(array)
|
|
70
|
+
? []
|
|
71
|
+
: array.slice(0, -1)) as unknown as ConstrainedList.ButLast<Ar>;
|
|
68
72
|
|
|
69
73
|
/**
|
|
70
74
|
* Takes the first N elements from an array.
|
|
@@ -89,25 +93,29 @@ export function take<
|
|
|
89
93
|
>(
|
|
90
94
|
array: Ar,
|
|
91
95
|
num: N,
|
|
92
|
-
):
|
|
93
|
-
?
|
|
94
|
-
: N extends
|
|
95
|
-
? Ar
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
96
|
+
): HasLengthConstraint<Ar> extends true
|
|
97
|
+
? readonly Ar[number][]
|
|
98
|
+
: N extends StructuralPrefixLength
|
|
99
|
+
? List.Take<N, Ar>
|
|
100
|
+
: N extends SizeType.ArgArrPositive
|
|
101
|
+
? Ar extends NonEmptyTuple<unknown>
|
|
102
|
+
? NonEmptyArray<Ar[number]>
|
|
103
|
+
: readonly Ar[number][]
|
|
104
|
+
: readonly Ar[number][];
|
|
99
105
|
|
|
100
106
|
export function take<N extends SizeType.ArgArr>(
|
|
101
107
|
num: N,
|
|
102
108
|
): <const Ar extends readonly unknown[]>(
|
|
103
109
|
array: Ar,
|
|
104
|
-
) =>
|
|
105
|
-
?
|
|
106
|
-
: N extends
|
|
107
|
-
? Ar
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
110
|
+
) => HasLengthConstraint<Ar> extends true
|
|
111
|
+
? readonly Ar[number][]
|
|
112
|
+
: N extends StructuralPrefixLength
|
|
113
|
+
? List.Take<N, Ar>
|
|
114
|
+
: N extends SizeType.ArgArrPositive
|
|
115
|
+
? Ar extends NonEmptyTuple<unknown>
|
|
116
|
+
? NonEmptyArray<Ar[number]>
|
|
117
|
+
: readonly Ar[number][]
|
|
118
|
+
: readonly Ar[number][];
|
|
111
119
|
|
|
112
120
|
export function take<E>(
|
|
113
121
|
...args:
|
|
@@ -151,25 +159,29 @@ export function takeLast<
|
|
|
151
159
|
>(
|
|
152
160
|
array: Ar,
|
|
153
161
|
num: N,
|
|
154
|
-
):
|
|
155
|
-
?
|
|
156
|
-
: N extends
|
|
157
|
-
? Ar
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
162
|
+
): HasLengthConstraint<Ar> extends true
|
|
163
|
+
? readonly Ar[number][]
|
|
164
|
+
: N extends StructuralPrefixLength
|
|
165
|
+
? List.TakeLast<N, Ar>
|
|
166
|
+
: N extends SizeType.ArgArrPositive
|
|
167
|
+
? Ar extends NonEmptyTuple<unknown>
|
|
168
|
+
? NonEmptyArray<Ar[number]>
|
|
169
|
+
: readonly Ar[number][]
|
|
170
|
+
: readonly Ar[number][];
|
|
161
171
|
|
|
162
172
|
export function takeLast<N extends SizeType.ArgArr>(
|
|
163
173
|
num: N,
|
|
164
174
|
): <const Ar extends readonly unknown[]>(
|
|
165
175
|
array: Ar,
|
|
166
|
-
) =>
|
|
167
|
-
?
|
|
168
|
-
: N extends
|
|
169
|
-
? Ar
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
176
|
+
) => HasLengthConstraint<Ar> extends true
|
|
177
|
+
? readonly Ar[number][]
|
|
178
|
+
: N extends StructuralPrefixLength
|
|
179
|
+
? List.TakeLast<N, Ar>
|
|
180
|
+
: N extends SizeType.ArgArrPositive
|
|
181
|
+
? Ar extends NonEmptyTuple<unknown>
|
|
182
|
+
? NonEmptyArray<Ar[number]>
|
|
183
|
+
: readonly Ar[number][]
|
|
184
|
+
: readonly Ar[number][];
|
|
173
185
|
|
|
174
186
|
export function takeLast<E>(
|
|
175
187
|
...args:
|
|
@@ -214,16 +226,22 @@ export function skip<
|
|
|
214
226
|
>(
|
|
215
227
|
array: Ar,
|
|
216
228
|
num: N,
|
|
217
|
-
):
|
|
229
|
+
): HasLengthConstraint<Ar> extends true
|
|
230
|
+
? readonly Ar[number][]
|
|
231
|
+
: N extends StructuralPrefixLength
|
|
232
|
+
? List.Skip<N, Ar>
|
|
233
|
+
: readonly Ar[number][];
|
|
218
234
|
|
|
219
235
|
// curried version
|
|
220
236
|
export function skip<N extends SizeType.ArgArr>(
|
|
221
237
|
num: N,
|
|
222
238
|
): <const Ar extends readonly unknown[]>(
|
|
223
239
|
array: Ar,
|
|
224
|
-
) =>
|
|
225
|
-
?
|
|
226
|
-
:
|
|
240
|
+
) => HasLengthConstraint<Ar> extends true
|
|
241
|
+
? readonly Ar[number][]
|
|
242
|
+
: N extends StructuralPrefixLength
|
|
243
|
+
? List.Skip<N, Ar>
|
|
244
|
+
: readonly Ar[number][];
|
|
227
245
|
|
|
228
246
|
export function skip<E>(
|
|
229
247
|
...args: readonly [readonly E[], SizeType.ArgArr] | readonly [SizeType.ArgArr]
|
|
@@ -265,18 +283,22 @@ export function skipLast<
|
|
|
265
283
|
>(
|
|
266
284
|
array: Ar,
|
|
267
285
|
num: N,
|
|
268
|
-
):
|
|
269
|
-
?
|
|
270
|
-
:
|
|
286
|
+
): HasLengthConstraint<Ar> extends true
|
|
287
|
+
? readonly Ar[number][]
|
|
288
|
+
: N extends StructuralPrefixLength
|
|
289
|
+
? List.SkipLast<N, Ar>
|
|
290
|
+
: readonly Ar[number][];
|
|
271
291
|
|
|
272
292
|
// curried version
|
|
273
293
|
export function skipLast<N extends SizeType.ArgArr>(
|
|
274
294
|
num: N,
|
|
275
295
|
): <const Ar extends readonly unknown[]>(
|
|
276
296
|
array: Ar,
|
|
277
|
-
) =>
|
|
278
|
-
?
|
|
279
|
-
:
|
|
297
|
+
) => HasLengthConstraint<Ar> extends true
|
|
298
|
+
? readonly Ar[number][]
|
|
299
|
+
: N extends StructuralPrefixLength
|
|
300
|
+
? List.SkipLast<N, Ar>
|
|
301
|
+
: readonly Ar[number][];
|
|
280
302
|
|
|
281
303
|
export function skipLast<E>(
|
|
282
304
|
...args:
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type MinLengthArray } from 'ts-type-forge';
|
|
1
2
|
import { expectType } from '../../expect-type.mjs';
|
|
2
3
|
import {
|
|
3
4
|
butLast,
|
|
@@ -219,3 +220,57 @@ describe('Arr slicing', () => {
|
|
|
219
220
|
});
|
|
220
221
|
});
|
|
221
222
|
});
|
|
223
|
+
|
|
224
|
+
/* Length-constrained inputs. `List.*` reports what it can see from a
|
|
225
|
+
fixed-length tuple, and a branded array's `length` is `number`, so it handed
|
|
226
|
+
the input type straight back — `tail` of an "at least 5" array claimed the
|
|
227
|
+
four-element result was still at least five. Never called; see the note in
|
|
228
|
+
`array-utils-modification.test.mts`. */
|
|
229
|
+
export const slicingTypeChecks = (
|
|
230
|
+
brandedFive: MinLengthArray<5, string>,
|
|
231
|
+
brandedAndTuple: MinLengthArray<3, number> & readonly [1, 2, 3, 4, 5],
|
|
232
|
+
): void => {
|
|
233
|
+
// The bound is recomputed rather than passed through.
|
|
234
|
+
const _tailed = tail(brandedFive);
|
|
235
|
+
|
|
236
|
+
expectType<typeof _tailed, MinLengthArray<4, string>>('~=');
|
|
237
|
+
|
|
238
|
+
const _butLasted = butLast(brandedFive);
|
|
239
|
+
|
|
240
|
+
expectType<typeof _butLasted, MinLengthArray<4, string>>('~=');
|
|
241
|
+
|
|
242
|
+
/* A brand intersected with an exact tuple keeps the positions too, so the
|
|
243
|
+
result is exact on both counts. */
|
|
244
|
+
const _tailedBoth = tail(brandedAndTuple);
|
|
245
|
+
|
|
246
|
+
expectType<(typeof _tailedBoth)[0], 2>('=');
|
|
247
|
+
|
|
248
|
+
expectType<(typeof _tailedBoth)['length'], 4>('=');
|
|
249
|
+
|
|
250
|
+
/* `take` / `takeLast` / `skip` / `skipLast` stay on the `List.*` path and give
|
|
251
|
+
a branded input the sound unconstrained answer instead of its stale brand.
|
|
252
|
+
They cannot use `ConstrainedList.Take` and friends: those rebuild the bounds
|
|
253
|
+
from `N` and cannot be instantiated against a still-generic `Ar` at all —
|
|
254
|
+
even with a literal `N` the deferred result is a union too complex to
|
|
255
|
+
represent. */
|
|
256
|
+
const _taken = take(brandedFive, 2);
|
|
257
|
+
|
|
258
|
+
expectType<typeof _taken, readonly string[]>('=');
|
|
259
|
+
|
|
260
|
+
const _skipped = skip(brandedFive, 2);
|
|
261
|
+
|
|
262
|
+
expectType<typeof _skipped, readonly string[]>('=');
|
|
263
|
+
|
|
264
|
+
// Plain tuples keep mapping exactly as before.
|
|
265
|
+
const _tailedTuple = tail([1, 2, 3] as const);
|
|
266
|
+
|
|
267
|
+
expectType<typeof _tailedTuple, readonly [2, 3]>('=');
|
|
268
|
+
|
|
269
|
+
const _butLastedTuple = butLast([1, 2, 3] as const);
|
|
270
|
+
|
|
271
|
+
expectType<typeof _butLastedTuple, readonly [1, 2]>('=');
|
|
272
|
+
|
|
273
|
+
const _takenTuple = take([1, 2, 3] as const, 2);
|
|
274
|
+
|
|
275
|
+
expectType<typeof _takenTuple, readonly [1, 2]>('=');
|
|
276
|
+
};
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
|
+
type BoundedLengthArray,
|
|
3
|
+
type ChangeArrayElement,
|
|
4
|
+
type ConstrainedList,
|
|
2
5
|
type FixedLengthTuple,
|
|
6
|
+
type HasLengthConstraint,
|
|
3
7
|
type IsFixedLengthList,
|
|
4
|
-
type List,
|
|
5
8
|
type NonEmptyArray,
|
|
6
9
|
type NonEmptyTuple,
|
|
7
10
|
type PositiveInt,
|
|
8
11
|
type PositiveUint32,
|
|
9
12
|
type Primitive,
|
|
10
13
|
type SafeUintWithSmallInt,
|
|
14
|
+
type SupportedLength,
|
|
15
|
+
type UnknownBrand,
|
|
11
16
|
type WithSmallInt,
|
|
12
17
|
} from 'ts-type-forge';
|
|
13
18
|
import { IMap } from '../../collections/index.mjs';
|
|
@@ -20,8 +25,8 @@ import {
|
|
|
20
25
|
type SizeType,
|
|
21
26
|
} from '../../types.mjs';
|
|
22
27
|
import { newArray, seq } from './array-utils-creation.mjs';
|
|
28
|
+
import { isNonEmpty } from './array-utils-length-bounded-array-guard.mjs';
|
|
23
29
|
import { size } from './array-utils-size.mjs';
|
|
24
|
-
import { isNonEmpty } from './array-utils-validation.mjs';
|
|
25
30
|
|
|
26
31
|
/**
|
|
27
32
|
* Creates a new array by transforming each element with a mapping function.
|
|
@@ -42,17 +47,41 @@ import { isNonEmpty } from './array-utils-validation.mjs';
|
|
|
42
47
|
* assert.deepStrictEqual(indexed, ['0:1', '1:2', '2:3']);
|
|
43
48
|
* ```
|
|
44
49
|
*/
|
|
50
|
+
export function map<const Ar extends readonly unknown[] & UnknownBrand, B>(
|
|
51
|
+
array: Ar,
|
|
52
|
+
mapFn: (a: Ar[number], index: ArrayIndex<Ar>) => B,
|
|
53
|
+
): ChangeArrayElement<Ar, B>;
|
|
54
|
+
|
|
55
|
+
// A plain array or tuple carries no length brand, so the homomorphic mapping
|
|
56
|
+
// is the whole answer. Stating it directly — rather than going through
|
|
57
|
+
// `ChangeArrayElement`, whose `HasLengthConstraint` test a *generic* `Ar`
|
|
58
|
+
// cannot decide — is what keeps `map` usable inside a function that is itself
|
|
59
|
+
// generic over the tuple: a deferred conditional is not assignable to the
|
|
60
|
+
// caller's own `{ [K in keyof Ar]: B }`, while this is.
|
|
45
61
|
export function map<const Ar extends readonly unknown[], B>(
|
|
46
62
|
array: Ar,
|
|
47
63
|
mapFn: (a: Ar[number], index: ArrayIndex<Ar>) => B,
|
|
48
64
|
): Readonly<{ [K in keyof Ar]: B }>;
|
|
49
65
|
|
|
50
66
|
// curried version
|
|
67
|
+
//
|
|
68
|
+
// The two cases have to be overloads *of the returned function*, not two
|
|
69
|
+
// overloads of `map` itself: both curried signatures take the same single
|
|
70
|
+
// argument, so overload resolution would always pick the first and the second
|
|
71
|
+
// would be dead.
|
|
72
|
+
//
|
|
73
|
+
// Spelled as an intersection of two function types rather than one object type
|
|
74
|
+
// carrying two call signatures — the `convert-to-readonly` codemod wraps an
|
|
75
|
+
// inline object type in `Readonly<…>`, and a mapped type drops call
|
|
76
|
+
// signatures, which would leave the curried form with none at all.
|
|
51
77
|
export function map<A, B>(
|
|
52
78
|
mapFn: (a: A, index: SizeType.Arr) => B,
|
|
53
|
-
): <const Ar extends readonly A[]>(
|
|
79
|
+
): (<const Ar extends readonly A[] & UnknownBrand>(
|
|
54
80
|
array: Ar,
|
|
55
|
-
) =>
|
|
81
|
+
) => ChangeArrayElement<Ar, B>) &
|
|
82
|
+
(<const Ar extends readonly A[]>(
|
|
83
|
+
array: Ar,
|
|
84
|
+
) => Readonly<{ [K in keyof Ar]: B }>);
|
|
56
85
|
|
|
57
86
|
export function map<A, B>(
|
|
58
87
|
...args:
|
|
@@ -187,7 +216,7 @@ const scanImpl = <E, S>(
|
|
|
187
216
|
*/
|
|
188
217
|
export const toReversed = <const Ar extends readonly unknown[]>(
|
|
189
218
|
array: Ar,
|
|
190
|
-
):
|
|
219
|
+
): ConstrainedList.Reverse<Ar> =>
|
|
191
220
|
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
192
221
|
array.toReversed() as never;
|
|
193
222
|
|
|
@@ -224,11 +253,13 @@ export const toSorted = <const Ar extends readonly unknown[]>(
|
|
|
224
253
|
comparator?: (x: Ar[number], y: Ar[number]) => number,
|
|
225
254
|
]
|
|
226
255
|
: readonly [array: Ar, comparator: (x: Ar[number], y: Ar[number]) => number]
|
|
227
|
-
):
|
|
228
|
-
?
|
|
229
|
-
: Ar extends
|
|
230
|
-
?
|
|
231
|
-
:
|
|
256
|
+
): HasLengthConstraint<Ar> extends true
|
|
257
|
+
? ChangeArrayElement<Ar, Ar[number]>
|
|
258
|
+
: IsFixedLengthList<Ar> extends true
|
|
259
|
+
? FixedLengthTuple<Ar['length'], Ar[number]>
|
|
260
|
+
: Ar extends NonEmptyTuple<unknown>
|
|
261
|
+
? NonEmptyArray<Ar[number]>
|
|
262
|
+
: readonly Ar[number][] =>
|
|
232
263
|
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
233
264
|
array.toSorted(
|
|
234
265
|
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
@@ -282,21 +313,25 @@ export function toSortedBy<const Ar extends readonly unknown[]>(
|
|
|
282
313
|
comparatorValueMapper: (value: Ar[number]) => number,
|
|
283
314
|
// If the array elements are mapped to numbers, comparator is optional.
|
|
284
315
|
comparator?: (x: number, y: number) => number,
|
|
285
|
-
):
|
|
286
|
-
?
|
|
287
|
-
: Ar extends
|
|
288
|
-
?
|
|
289
|
-
:
|
|
316
|
+
): HasLengthConstraint<Ar> extends true
|
|
317
|
+
? ChangeArrayElement<Ar, Ar[number]>
|
|
318
|
+
: IsFixedLengthList<Ar> extends true
|
|
319
|
+
? FixedLengthTuple<Ar['length'], Ar[number]>
|
|
320
|
+
: Ar extends NonEmptyTuple<unknown>
|
|
321
|
+
? NonEmptyArray<Ar[number]>
|
|
322
|
+
: readonly Ar[number][];
|
|
290
323
|
|
|
291
324
|
export function toSortedBy<const Ar extends readonly unknown[], const V>(
|
|
292
325
|
array: Ar,
|
|
293
326
|
comparatorValueMapper: (value: Ar[number]) => V,
|
|
294
327
|
comparator: (x: V, y: V) => number,
|
|
295
|
-
):
|
|
296
|
-
?
|
|
297
|
-
: Ar extends
|
|
298
|
-
?
|
|
299
|
-
:
|
|
328
|
+
): HasLengthConstraint<Ar> extends true
|
|
329
|
+
? ChangeArrayElement<Ar, Ar[number]>
|
|
330
|
+
: IsFixedLengthList<Ar> extends true
|
|
331
|
+
? FixedLengthTuple<Ar['length'], Ar[number]>
|
|
332
|
+
: Ar extends NonEmptyTuple<unknown>
|
|
333
|
+
? NonEmptyArray<Ar[number]>
|
|
334
|
+
: readonly Ar[number][];
|
|
300
335
|
|
|
301
336
|
export function toSortedBy<E, const V>(
|
|
302
337
|
array: readonly E[],
|
|
@@ -627,18 +662,24 @@ export function flatMap<A, B>(
|
|
|
627
662
|
*
|
|
628
663
|
* const triples = Arr.partition(3)(values);
|
|
629
664
|
*
|
|
665
|
+
* // Every chunk is branded `BoundedLengthArray<1, N, …>` — `partition` never
|
|
666
|
+
* // emits an empty chunk — so the expected values are annotated with the
|
|
667
|
+
* // unbranded type.
|
|
630
668
|
* const expectedPairs = [[1, 2], [3, 4], [5]] as const;
|
|
631
669
|
*
|
|
632
|
-
* assert.deepStrictEqual(
|
|
670
|
+
* assert.deepStrictEqual<readonly (readonly number[])[]>(
|
|
671
|
+
* pairs,
|
|
672
|
+
* expectedPairs,
|
|
673
|
+
* );
|
|
633
674
|
*
|
|
634
|
-
* assert.deepStrictEqual(triples, [
|
|
675
|
+
* assert.deepStrictEqual<readonly (readonly number[])[]>(triples, [
|
|
635
676
|
* [1, 2, 3],
|
|
636
677
|
* [4, 5],
|
|
637
678
|
* ]);
|
|
638
679
|
*
|
|
639
680
|
* const pairs2 = Arr.chunk([1, 2, 3, 4, 5, 6], 2);
|
|
640
681
|
*
|
|
641
|
-
* assert.deepStrictEqual(pairs2, [
|
|
682
|
+
* assert.deepStrictEqual<readonly (readonly number[])[]>(pairs2, [
|
|
642
683
|
* [1, 2],
|
|
643
684
|
* [3, 4],
|
|
644
685
|
* [5, 6],
|
|
@@ -646,17 +687,17 @@ export function flatMap<A, B>(
|
|
|
646
687
|
* ```
|
|
647
688
|
*/
|
|
648
689
|
export function partition<
|
|
649
|
-
N extends WithSmallInt<PositiveInt & SizeType.Arr>,
|
|
650
690
|
E,
|
|
651
|
-
|
|
691
|
+
N extends WithSmallInt<PositiveInt & SizeType.Arr>,
|
|
692
|
+
>(array: readonly E[], chunkSize: N): readonly PartitionChunk<N, E>[];
|
|
652
693
|
|
|
653
694
|
export function partition<N extends WithSmallInt<PositiveInt & SizeType.Arr>>(
|
|
654
695
|
chunkSize: N,
|
|
655
|
-
): <E>(array: readonly E[]) => readonly
|
|
696
|
+
): <E>(array: readonly E[]) => readonly PartitionChunk<N, E>[];
|
|
656
697
|
|
|
657
698
|
export function partition<
|
|
658
|
-
N extends WithSmallInt<PositiveInt & SizeType.Arr>,
|
|
659
699
|
E,
|
|
700
|
+
N extends WithSmallInt<PositiveInt & SizeType.Arr>,
|
|
660
701
|
>(
|
|
661
702
|
...args:
|
|
662
703
|
readonly [array: readonly E[], chunkSize: N] | readonly [chunkSize: N]
|
|
@@ -672,7 +713,20 @@ export function partition<
|
|
|
672
713
|
}
|
|
673
714
|
}
|
|
674
715
|
|
|
675
|
-
|
|
716
|
+
/**
|
|
717
|
+
* Element type of {@link partition}'s result: a chunk holds between 1 and `N`
|
|
718
|
+
* elements. The lower bound is what makes this worth spelling out — `partition`
|
|
719
|
+
* never emits an empty chunk, so indexed access into a chunk is not
|
|
720
|
+
* `undefined` at position `0`, unlike with a plain `readonly E[]`.
|
|
721
|
+
*
|
|
722
|
+
* Falls back to {@link NonEmptyArray} when `N` is not a bound the brand can
|
|
723
|
+
* express, which keeps that lower bound in every case.
|
|
724
|
+
*/
|
|
725
|
+
type PartitionChunk<N, E> = N extends SupportedLength
|
|
726
|
+
? BoundedLengthArray<1, N, E>
|
|
727
|
+
: NonEmptyArray<E>;
|
|
728
|
+
|
|
729
|
+
const partitionImpl = <E, N extends WithSmallInt<PositiveInt & SizeType.Arr>>(
|
|
676
730
|
array: readonly E[],
|
|
677
731
|
chunkSize: N,
|
|
678
732
|
): readonly (readonly E[])[] =>
|
|
@@ -683,6 +737,13 @@ const partitionImpl = <N extends WithSmallInt<PositiveInt & SizeType.Arr>, E>(
|
|
|
683
737
|
array.slice(chunkSize * i, chunkSize * (i + 1)),
|
|
684
738
|
);
|
|
685
739
|
|
|
740
|
+
/**
|
|
741
|
+
* Alias for `partition`.
|
|
742
|
+
*
|
|
743
|
+
* @see {@link partition}
|
|
744
|
+
*/
|
|
745
|
+
export const chunk = partition;
|
|
746
|
+
|
|
686
747
|
/**
|
|
687
748
|
* Concatenates two arrays.
|
|
688
749
|
*
|
|
@@ -853,20 +914,13 @@ export const zip = <
|
|
|
853
914
|
>(
|
|
854
915
|
array1: Ar1,
|
|
855
916
|
array2: Ar2,
|
|
856
|
-
):
|
|
917
|
+
): ConstrainedList.Zip<Ar1, Ar2> =>
|
|
857
918
|
// eslint-disable-next-line total-functions/no-unsafe-type-assertion
|
|
858
919
|
seq(Uint32.min(size(array1), size(array2))).map((i: Uint32) =>
|
|
859
920
|
// Non-null assertion is safe here because `i` is always within bounds of both arrays up to the length of the shorter one.
|
|
860
921
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
861
922
|
tp(array1[i]!, array2[i]!),
|
|
862
|
-
) as unknown as
|
|
863
|
-
|
|
864
|
-
/**
|
|
865
|
-
* Alias for `partition`.
|
|
866
|
-
*
|
|
867
|
-
* @see {@link partition}
|
|
868
|
-
*/
|
|
869
|
-
export const chunk = partition;
|
|
923
|
+
) as unknown as ConstrainedList.Zip<Ar1, Ar2>;
|
|
870
924
|
|
|
871
925
|
/**
|
|
872
926
|
* Computes the cartesian product of arrays.
|