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,8 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type BoundedLengthArray,
|
|
3
|
+
type FixedLengthTuple,
|
|
4
|
+
type MinLengthArray,
|
|
5
|
+
type NonEmptyArray,
|
|
6
|
+
type NonEmptyTuple,
|
|
7
|
+
} from 'ts-type-forge';
|
|
2
8
|
import { IMap } from '../../collections/index.mjs';
|
|
3
9
|
import { expectType } from '../../expect-type.mjs';
|
|
4
10
|
import { Optional } from '../../functional/index.mjs';
|
|
5
11
|
import { SafeUint } from '../../number/index.mjs';
|
|
12
|
+
import { asMinLengthArray } from './array-utils-length-bounded-array-cast.mjs';
|
|
6
13
|
import {
|
|
7
14
|
cartesianProduct,
|
|
8
15
|
concat,
|
|
@@ -47,7 +54,7 @@ describe('Arr transformations', () => {
|
|
|
47
54
|
|
|
48
55
|
const mappedMixed = map(mixed, (x) => typeof x);
|
|
49
56
|
|
|
50
|
-
expectType<typeof mappedMixed,
|
|
57
|
+
expectType<typeof mappedMixed, FixedLengthTuple<3, string>>('<=');
|
|
51
58
|
|
|
52
59
|
assert.deepStrictEqual(mappedMixed, ['number', 'string', 'boolean']);
|
|
53
60
|
});
|
|
@@ -57,12 +64,37 @@ describe('Arr transformations', () => {
|
|
|
57
64
|
|
|
58
65
|
const mappedWithIndex = map(tuple, (x, i) => `${i}:${x}`);
|
|
59
66
|
|
|
60
|
-
expectType<typeof mappedWithIndex,
|
|
61
|
-
'<=',
|
|
62
|
-
);
|
|
67
|
+
expectType<typeof mappedWithIndex, FixedLengthTuple<3, string>>('<=');
|
|
63
68
|
|
|
64
69
|
assert.deepStrictEqual(mappedWithIndex, ['0:a', '1:b', '2:c']);
|
|
65
70
|
});
|
|
71
|
+
|
|
72
|
+
test('should preserve the tuple shape under a generic parameter', () => {
|
|
73
|
+
// A caller that is itself generic over the tuple cannot resolve a
|
|
74
|
+
// conditional return type, so `map` has to report the homomorphic
|
|
75
|
+
// mapping directly for a parameter that carries no length brand.
|
|
76
|
+
const mapValues = <const T extends readonly Readonly<{ v: unknown }>[]>(
|
|
77
|
+
boxes: T,
|
|
78
|
+
): Readonly<{ [K in keyof T]: unknown }> => map(boxes, (b) => b.v);
|
|
79
|
+
|
|
80
|
+
const result = mapValues([{ v: 1 }, { v: 'a' }] as const);
|
|
81
|
+
|
|
82
|
+
expectType<typeof result, FixedLengthTuple<2, unknown>>('=');
|
|
83
|
+
|
|
84
|
+
assert.deepStrictEqual<FixedLengthTuple<2, unknown>>(result, [1, 'a']);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test('should keep the length brand of a branded array', () => {
|
|
88
|
+
const lower: MinLengthArray<2, number> = asMinLengthArray(2, [1, 2, 3]);
|
|
89
|
+
|
|
90
|
+
const mappedLower = map(lower, String);
|
|
91
|
+
|
|
92
|
+
expectType<typeof mappedLower, MinLengthArray<2, string>>('~=');
|
|
93
|
+
|
|
94
|
+
// The brand is not part of the runtime value, so compare structurally —
|
|
95
|
+
// the type argument is what widens it, no intermediate binding needed.
|
|
96
|
+
assert.deepStrictEqual<readonly string[]>(mappedLower, ['1', '2', '3']);
|
|
97
|
+
});
|
|
66
98
|
});
|
|
67
99
|
|
|
68
100
|
describe(scan, () => {
|
|
@@ -71,7 +103,7 @@ describe('Arr transformations', () => {
|
|
|
71
103
|
|
|
72
104
|
const runningSum = scan(numbers, (acc, curr) => acc + curr, 0);
|
|
73
105
|
|
|
74
|
-
expectType<typeof runningSum,
|
|
106
|
+
expectType<typeof runningSum, NonEmptyTuple<number>>('<=');
|
|
75
107
|
|
|
76
108
|
assert.deepStrictEqual<readonly number[]>(runningSum, [0, 1, 3, 6, 10]);
|
|
77
109
|
});
|
|
@@ -129,7 +161,7 @@ describe('Arr transformations', () => {
|
|
|
129
161
|
|
|
130
162
|
const result = scan(strings, (acc, curr) => acc + curr.length, 0);
|
|
131
163
|
|
|
132
|
-
expectType<typeof result,
|
|
164
|
+
expectType<typeof result, NonEmptyTuple<number>>('<=');
|
|
133
165
|
|
|
134
166
|
assert.deepStrictEqual<readonly number[]>(result, [0, 1, 2, 3]);
|
|
135
167
|
});
|
|
@@ -644,13 +676,15 @@ describe('Arr transformations', () => {
|
|
|
644
676
|
|
|
645
677
|
expectType<
|
|
646
678
|
typeof result,
|
|
647
|
-
readonly
|
|
679
|
+
readonly BoundedLengthArray<
|
|
680
|
+
1,
|
|
681
|
+
4,
|
|
648
682
|
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
|
|
649
|
-
|
|
650
|
-
>('
|
|
683
|
+
>[]
|
|
684
|
+
>('~=');
|
|
651
685
|
|
|
652
686
|
test('case 1', () => {
|
|
653
|
-
assert.deepStrictEqual(result, [
|
|
687
|
+
assert.deepStrictEqual<readonly (readonly number[])[]>(result, [
|
|
654
688
|
[1, 2, 3, 4],
|
|
655
689
|
[5, 6, 7, 8],
|
|
656
690
|
[9, 10, 11, 12],
|
|
@@ -663,13 +697,15 @@ describe('Arr transformations', () => {
|
|
|
663
697
|
|
|
664
698
|
expectType<
|
|
665
699
|
typeof result,
|
|
666
|
-
readonly
|
|
700
|
+
readonly BoundedLengthArray<
|
|
701
|
+
1,
|
|
702
|
+
3,
|
|
667
703
|
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
|
|
668
|
-
|
|
669
|
-
>('
|
|
704
|
+
>[]
|
|
705
|
+
>('~=');
|
|
670
706
|
|
|
671
707
|
test('case 2', () => {
|
|
672
|
-
assert.deepStrictEqual(result, [
|
|
708
|
+
assert.deepStrictEqual<readonly (readonly number[])[]>(result, [
|
|
673
709
|
[1, 2, 3],
|
|
674
710
|
[4, 5, 6],
|
|
675
711
|
[7, 8, 9],
|
|
@@ -683,13 +719,15 @@ describe('Arr transformations', () => {
|
|
|
683
719
|
|
|
684
720
|
expectType<
|
|
685
721
|
typeof result,
|
|
686
|
-
readonly
|
|
722
|
+
readonly BoundedLengthArray<
|
|
723
|
+
1,
|
|
724
|
+
5,
|
|
687
725
|
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
|
|
688
|
-
|
|
689
|
-
>('
|
|
726
|
+
>[]
|
|
727
|
+
>('~=');
|
|
690
728
|
|
|
691
729
|
test('case 3', () => {
|
|
692
|
-
assert.deepStrictEqual(result, [
|
|
730
|
+
assert.deepStrictEqual<readonly (readonly number[])[]>(result, [
|
|
693
731
|
[1, 2, 3, 4, 5],
|
|
694
732
|
[6, 7, 8, 9, 10],
|
|
695
733
|
[11, 12],
|
|
@@ -702,7 +740,7 @@ describe('Arr transformations', () => {
|
|
|
702
740
|
|
|
703
741
|
const result = partition(numbers, 2);
|
|
704
742
|
|
|
705
|
-
assert.deepStrictEqual(result, [
|
|
743
|
+
assert.deepStrictEqual<readonly (readonly number[])[]>(result, [
|
|
706
744
|
[1, 2],
|
|
707
745
|
[3, 4],
|
|
708
746
|
[5, 6],
|
|
@@ -714,7 +752,11 @@ describe('Arr transformations', () => {
|
|
|
714
752
|
|
|
715
753
|
const result = partition(numbers, 2);
|
|
716
754
|
|
|
717
|
-
assert.deepStrictEqual(
|
|
755
|
+
assert.deepStrictEqual<readonly (readonly number[])[]>(result, [
|
|
756
|
+
[1, 2],
|
|
757
|
+
[3, 4],
|
|
758
|
+
[5],
|
|
759
|
+
]);
|
|
718
760
|
});
|
|
719
761
|
|
|
720
762
|
test('should work with chunk size < 2 (returns empty)', () => {
|
|
@@ -731,7 +773,7 @@ describe('Arr transformations', () => {
|
|
|
731
773
|
|
|
732
774
|
const result = partition(numbers, 5);
|
|
733
775
|
|
|
734
|
-
assert.deepStrictEqual(result, [[1, 2]]);
|
|
776
|
+
assert.deepStrictEqual<readonly (readonly number[])[]>(result, [[1, 2]]);
|
|
735
777
|
});
|
|
736
778
|
|
|
737
779
|
test('partition should work with empty array', () => {
|
|
@@ -1000,7 +1042,7 @@ describe('Arr transformations', () => {
|
|
|
1000
1042
|
|
|
1001
1043
|
const zipped = zip(xs, ys);
|
|
1002
1044
|
|
|
1003
|
-
expectType<typeof zipped, readonly
|
|
1045
|
+
expectType<typeof zipped, readonly FixedLengthTuple<2, number>[]>('=');
|
|
1004
1046
|
|
|
1005
1047
|
test('case 2', () => {
|
|
1006
1048
|
assert.deepStrictEqual(zipped, [[1, 4]]);
|
|
@@ -1162,3 +1204,34 @@ describe('Arr transformations', () => {
|
|
|
1162
1204
|
});
|
|
1163
1205
|
});
|
|
1164
1206
|
});
|
|
1207
|
+
|
|
1208
|
+
/* `toReversed` is a known permutation, so the tuple half can be reversed
|
|
1209
|
+
alongside the brand. It used to fall back to `ChangeArrayElement`, which kept
|
|
1210
|
+
the length but collapsed the positions to their union. Never called; see the
|
|
1211
|
+
note in `array-utils-modification.test.mts`. */
|
|
1212
|
+
export const reversedTypeChecks = (
|
|
1213
|
+
brandedFive: MinLengthArray<5, string>,
|
|
1214
|
+
brandedAndTuple: MinLengthArray<3, number> & readonly [1, 2, 3, 4, 5],
|
|
1215
|
+
): void => {
|
|
1216
|
+
const _reversedBranded = toReversed(brandedFive);
|
|
1217
|
+
|
|
1218
|
+
expectType<typeof _reversedBranded, MinLengthArray<5, string>>('~=');
|
|
1219
|
+
|
|
1220
|
+
// Brand and positions both survive, and the positions really are reversed.
|
|
1221
|
+
const _reversedBoth = toReversed(brandedAndTuple);
|
|
1222
|
+
|
|
1223
|
+
expectType<(typeof _reversedBoth)[0], 5>('=');
|
|
1224
|
+
|
|
1225
|
+
expectType<(typeof _reversedBoth)[4], 1>('=');
|
|
1226
|
+
|
|
1227
|
+
const _reversedTuple = toReversed([1, 2, 3] as const);
|
|
1228
|
+
|
|
1229
|
+
expectType<typeof _reversedTuple, readonly [3, 2, 1]>('=');
|
|
1230
|
+
|
|
1231
|
+
/* `toSorted` deliberately does NOT take this path: an arbitrary permutation
|
|
1232
|
+
cannot keep positions, so the honest answer stays "same length, element
|
|
1233
|
+
type widened to the union". */
|
|
1234
|
+
const _sortedTuple = toSorted([1, 2, 3] as const);
|
|
1235
|
+
|
|
1236
|
+
expectType<typeof _sortedTuple, FixedLengthTuple<3, 1 | 2 | 3>>('~=');
|
|
1237
|
+
};
|
|
@@ -1,13 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type BoolOr,
|
|
3
|
-
type BoundedLengthTuple,
|
|
4
|
-
type FixedLengthArray,
|
|
5
|
-
type FixedLengthTuple,
|
|
6
|
-
type MaxLengthTuple,
|
|
7
|
-
type MinLengthArray,
|
|
8
|
-
type MinLengthTuple,
|
|
9
|
-
type TypeEq,
|
|
10
|
-
} from 'ts-type-forge';
|
|
1
|
+
import { type BoolOr, type IsAny, type IsUnknown } from 'ts-type-forge';
|
|
11
2
|
import { asUint32, Num } from '../../number/index.mjs';
|
|
12
3
|
import { type ArrayIndex, type SizeType } from '../../types.mjs';
|
|
13
4
|
|
|
@@ -34,8 +25,7 @@ export const isArray = <E,>(value: E): value is FilterArray<E> =>
|
|
|
34
25
|
Array.isArray(value);
|
|
35
26
|
|
|
36
27
|
type FilterArray<T> = T extends T
|
|
37
|
-
?
|
|
38
|
-
BoolOr<TypeEq<T, unknown>, TypeEq<T, any>> extends true
|
|
28
|
+
? BoolOr<IsUnknown<T>, IsAny<T>> extends true
|
|
39
29
|
? Cast<readonly unknown[], T>
|
|
40
30
|
: T extends readonly unknown[]
|
|
41
31
|
? T
|
|
@@ -46,156 +36,6 @@ type Cast<A, B> = A extends B ? A : never;
|
|
|
46
36
|
|
|
47
37
|
// validation
|
|
48
38
|
|
|
49
|
-
/**
|
|
50
|
-
* Type guard that checks if an array is empty.
|
|
51
|
-
*
|
|
52
|
-
* @example
|
|
53
|
-
*
|
|
54
|
-
* ```ts
|
|
55
|
-
* const emptyNumbers: readonly number[] = [] as const;
|
|
56
|
-
*
|
|
57
|
-
* const words = ['Ada', 'Lovelace'] as const;
|
|
58
|
-
*
|
|
59
|
-
* assert.isTrue(Arr.isEmpty(emptyNumbers));
|
|
60
|
-
*
|
|
61
|
-
* assert.isFalse(Arr.isEmpty(words));
|
|
62
|
-
*
|
|
63
|
-
* if (Arr.isEmpty(emptyNumbers)) {
|
|
64
|
-
* // `isEmpty` narrows to the branded `FixedLengthArray<0, number>`, so the
|
|
65
|
-
* // expected value is annotated with the unbranded type.
|
|
66
|
-
* assert.deepStrictEqual<readonly number[]>(emptyNumbers, []);
|
|
67
|
-
* }
|
|
68
|
-
* ```
|
|
69
|
-
*/
|
|
70
|
-
export const isEmpty = <Xs extends readonly unknown[]>(
|
|
71
|
-
array: Xs,
|
|
72
|
-
): array is FixedLengthArray<0, Xs[number]> & Xs => array.length === 0;
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Type guard that checks if an array is non-empty.
|
|
76
|
-
*
|
|
77
|
-
* @example
|
|
78
|
-
*
|
|
79
|
-
* ```ts
|
|
80
|
-
* const users: readonly Readonly<{ id: number }>[] = [{ id: 1 }] as const;
|
|
81
|
-
*
|
|
82
|
-
* const emptyUsers: readonly Readonly<{ id: number }>[] = [] as const;
|
|
83
|
-
*
|
|
84
|
-
* assert.isTrue(Arr.isNonEmpty(users));
|
|
85
|
-
*
|
|
86
|
-
* assert.isFalse(Arr.isNonEmpty(emptyUsers));
|
|
87
|
-
*
|
|
88
|
-
* if (Arr.isNonEmpty(users)) {
|
|
89
|
-
* assert.deepStrictEqual(users[0], { id: 1 });
|
|
90
|
-
* }
|
|
91
|
-
* ```
|
|
92
|
-
*/
|
|
93
|
-
export const isNonEmpty = <Xs extends readonly unknown[]>(
|
|
94
|
-
array: Xs,
|
|
95
|
-
): array is MinLengthArray<1, Xs[number]> & Xs => array.length > 0;
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Checks if an array has a specific length.
|
|
99
|
-
*
|
|
100
|
-
* @example
|
|
101
|
-
*
|
|
102
|
-
* ```ts
|
|
103
|
-
* const pair: readonly number[] = [1, 2] as const;
|
|
104
|
-
*
|
|
105
|
-
* const triple: readonly number[] = [1, 2, 3] as const;
|
|
106
|
-
*
|
|
107
|
-
* assert.isTrue(Arr.isFixedLengthTuple(pair, 2));
|
|
108
|
-
*
|
|
109
|
-
* assert.isFalse(Arr.isFixedLengthTuple(triple, 2));
|
|
110
|
-
*
|
|
111
|
-
* if (Arr.isFixedLengthTuple(pair, 2)) {
|
|
112
|
-
* assert.deepStrictEqual(pair, [1, 2]);
|
|
113
|
-
* }
|
|
114
|
-
* ```
|
|
115
|
-
*/
|
|
116
|
-
export const isFixedLengthTuple = <E, N extends SizeType.ArgArr>(
|
|
117
|
-
array: readonly E[],
|
|
118
|
-
len: N,
|
|
119
|
-
): array is FixedLengthTuple<N, E> => array.length === len;
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Checks if an array has at least a specific length.
|
|
123
|
-
*
|
|
124
|
-
* @example
|
|
125
|
-
*
|
|
126
|
-
* ```ts
|
|
127
|
-
* const queue: readonly string[] = ['task-1', 'task-2'] as const;
|
|
128
|
-
*
|
|
129
|
-
* const emptyQueue: readonly string[] = [] as const;
|
|
130
|
-
*
|
|
131
|
-
* assert.isTrue(Arr.isMinLengthTuple(queue, 1));
|
|
132
|
-
*
|
|
133
|
-
* assert.isFalse(Arr.isMinLengthTuple(emptyQueue, 1));
|
|
134
|
-
*
|
|
135
|
-
* if (Arr.isMinLengthTuple(queue, 1)) {
|
|
136
|
-
* assert.isTrue(queue[0] === 'task-1');
|
|
137
|
-
* }
|
|
138
|
-
* ```
|
|
139
|
-
*/
|
|
140
|
-
export const isMinLengthTuple = <E, N extends SizeType.ArgArr>(
|
|
141
|
-
array: readonly E[],
|
|
142
|
-
len: N,
|
|
143
|
-
): array is MinLengthTuple<N, E> => array.length >= len;
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Checks if an array has at most a specific length.
|
|
147
|
-
*
|
|
148
|
-
* @example
|
|
149
|
-
*
|
|
150
|
-
* ```ts
|
|
151
|
-
* const pair: readonly number[] = [1, 2] as const;
|
|
152
|
-
*
|
|
153
|
-
* const triple: readonly number[] = [1, 2, 3] as const;
|
|
154
|
-
*
|
|
155
|
-
* assert.isTrue(Arr.isMaxLengthTuple(pair, 2));
|
|
156
|
-
*
|
|
157
|
-
* assert.isFalse(Arr.isMaxLengthTuple(triple, 2));
|
|
158
|
-
*
|
|
159
|
-
* if (Arr.isMaxLengthTuple(pair, 2)) {
|
|
160
|
-
* assert.isTrue(pair.length <= 2);
|
|
161
|
-
* }
|
|
162
|
-
* ```
|
|
163
|
-
*/
|
|
164
|
-
export const isMaxLengthTuple = <E, N extends SizeType.ArgArr>(
|
|
165
|
-
array: readonly E[],
|
|
166
|
-
len: N,
|
|
167
|
-
): array is MaxLengthTuple<N, E> => array.length <= len;
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Checks if an array's length is within a specific inclusive range.
|
|
171
|
-
*
|
|
172
|
-
* @example
|
|
173
|
-
*
|
|
174
|
-
* ```ts
|
|
175
|
-
* const pair: readonly number[] = [1, 2] as const;
|
|
176
|
-
*
|
|
177
|
-
* const quad: readonly number[] = [1, 2, 3, 4] as const;
|
|
178
|
-
*
|
|
179
|
-
* assert.isTrue(Arr.isBoundedLengthTuple(pair, 1, 3));
|
|
180
|
-
*
|
|
181
|
-
* assert.isFalse(Arr.isBoundedLengthTuple(quad, 1, 3));
|
|
182
|
-
*
|
|
183
|
-
* if (Arr.isBoundedLengthTuple(pair, 1, 3)) {
|
|
184
|
-
* assert.isTrue(pair.length >= 1 && pair.length <= 3);
|
|
185
|
-
* }
|
|
186
|
-
* ```
|
|
187
|
-
*/
|
|
188
|
-
export const isBoundedLengthTuple = <
|
|
189
|
-
E,
|
|
190
|
-
Min extends SizeType.ArgArr,
|
|
191
|
-
Max extends SizeType.ArgArr,
|
|
192
|
-
>(
|
|
193
|
-
array: readonly E[],
|
|
194
|
-
min: Min,
|
|
195
|
-
max: Max,
|
|
196
|
-
): array is BoundedLengthTuple<Min, Max, E> =>
|
|
197
|
-
array.length >= min && array.length <= max;
|
|
198
|
-
|
|
199
39
|
/**
|
|
200
40
|
* Tests whether all elements in an array pass a test implemented by a predicate.
|
|
201
41
|
*
|