ts-data-forge 9.0.1 → 10.0.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.
- package/README.md +1 -1
- package/dist/array/impl/array-utils-creation.d.mts +4 -4
- 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-modification.d.mts +7 -7
- 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-transformation.d.mts +4 -4
- package/dist/array/impl/array-utils-transformation.d.mts.map +1 -1
- package/dist/array/impl/array-utils-transformation.mjs.map +1 -1
- package/dist/array/impl/array-utils-validation.d.mts +17 -17
- package/dist/array/impl/array-utils-validation.d.mts.map +1 -1
- package/dist/array/impl/array-utils-validation.mjs +5 -5
- package/dist/array/impl/array-utils-validation.mjs.map +1 -1
- package/dist/array/impl/index.mjs +1 -1
- package/dist/entry-point.mjs +2 -0
- package/dist/entry-point.mjs.map +1 -1
- package/dist/guard/as-length-bounded-array.d.mts +117 -0
- package/dist/guard/as-length-bounded-array.d.mts.map +1 -0
- package/dist/guard/as-length-bounded-array.mjs +37 -0
- package/dist/guard/as-length-bounded-array.mjs.map +1 -0
- package/dist/guard/index.d.mts +2 -0
- package/dist/guard/index.d.mts.map +1 -1
- package/dist/guard/index.mjs +2 -0
- package/dist/guard/index.mjs.map +1 -1
- package/dist/guard/is-length-bounded-array.d.mts +159 -0
- package/dist/guard/is-length-bounded-array.d.mts.map +1 -0
- package/dist/guard/is-length-bounded-array.mjs +7 -0
- package/dist/guard/is-length-bounded-array.mjs.map +1 -0
- package/dist/guard/is-length-bounded-string.d.mts +5 -6
- package/dist/guard/is-length-bounded-string.d.mts.map +1 -1
- package/dist/guard/is-length-bounded-string.mjs.map +1 -1
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -7
- package/src/array/impl/array-utils-creation.mts +3 -3
- package/src/array/impl/array-utils-modification.mts +7 -7
- package/src/array/impl/array-utils-modification.test.mts +4 -4
- package/src/array/impl/array-utils-transformation.mts +4 -4
- package/src/array/impl/array-utils-transformation.test.mts +7 -7
- package/src/array/impl/array-utils-validation.mts +24 -24
- package/src/array/impl/array-utils-validation.test.mts +94 -92
- package/src/collections/queue.test.mts +1 -1
- package/src/guard/as-length-bounded-array.mts +190 -0
- package/src/guard/as-length-bounded-array.test.mts +118 -0
- package/src/guard/index.mts +2 -0
- package/src/guard/is-length-bounded-array.mts +195 -0
- package/src/guard/is-length-bounded-array.test.mts +169 -0
- package/src/guard/is-length-bounded-string.mts +6 -6
- package/src/object/object.test.mts +3 -3
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
|
-
type
|
|
3
|
-
type
|
|
4
|
-
type
|
|
5
|
-
type
|
|
2
|
+
type BoundedLengthTuple,
|
|
3
|
+
type FixedLengthTuple,
|
|
4
|
+
type MaxLengthTuple,
|
|
5
|
+
type MinLengthTuple,
|
|
6
6
|
} from 'ts-type-forge';
|
|
7
7
|
import { expectType } from '../../expect-type.mjs';
|
|
8
8
|
import {
|
|
9
9
|
every,
|
|
10
10
|
indexIsInRange,
|
|
11
11
|
isArray,
|
|
12
|
-
|
|
13
|
-
isArrayAtMostLength,
|
|
14
|
-
isArrayBoundedLength,
|
|
15
|
-
isArrayOfLength,
|
|
12
|
+
isBoundedLengthTuple,
|
|
16
13
|
isEmpty,
|
|
14
|
+
isFixedLengthTuple,
|
|
15
|
+
isMaxLengthTuple,
|
|
16
|
+
isMinLengthTuple,
|
|
17
17
|
isNonEmpty,
|
|
18
18
|
some,
|
|
19
19
|
} from './array-utils-validation.mjs';
|
|
@@ -416,13 +416,13 @@ describe('Arr validations', () => {
|
|
|
416
416
|
});
|
|
417
417
|
});
|
|
418
418
|
|
|
419
|
-
describe(
|
|
419
|
+
describe(isFixedLengthTuple, () => {
|
|
420
420
|
test('should return true if array has specified length', () => {
|
|
421
421
|
const arr = [1, 2, 3] as const;
|
|
422
422
|
|
|
423
|
-
assert.isTrue(
|
|
423
|
+
assert.isTrue(isFixedLengthTuple(arr, 3));
|
|
424
424
|
|
|
425
|
-
if (
|
|
425
|
+
if (isFixedLengthTuple(arr, 3)) {
|
|
426
426
|
expectType<typeof arr, readonly [1, 2, 3]>('=');
|
|
427
427
|
}
|
|
428
428
|
});
|
|
@@ -430,15 +430,15 @@ describe('Arr validations', () => {
|
|
|
430
430
|
test('should return false if array does not have specified length', () => {
|
|
431
431
|
const arr = [1, 2, 3] as const;
|
|
432
432
|
|
|
433
|
-
assert.isFalse(
|
|
433
|
+
assert.isFalse(isFixedLengthTuple(arr, 2));
|
|
434
434
|
});
|
|
435
435
|
|
|
436
436
|
test('should return true for empty array and length 0', () => {
|
|
437
437
|
const arr = [] as const;
|
|
438
438
|
|
|
439
|
-
assert.isTrue(
|
|
439
|
+
assert.isTrue(isFixedLengthTuple(arr, 0));
|
|
440
440
|
|
|
441
|
-
if (
|
|
441
|
+
if (isFixedLengthTuple(arr, 0)) {
|
|
442
442
|
expectType<typeof arr, readonly []>('=');
|
|
443
443
|
}
|
|
444
444
|
});
|
|
@@ -446,74 +446,74 @@ describe('Arr validations', () => {
|
|
|
446
446
|
test('should return false for non-empty array and length 0', () => {
|
|
447
447
|
const arr = [1] as const;
|
|
448
448
|
|
|
449
|
-
assert.isFalse(
|
|
449
|
+
assert.isFalse(isFixedLengthTuple(arr, 0));
|
|
450
450
|
});
|
|
451
451
|
|
|
452
452
|
test('should work with unknown array type', () => {
|
|
453
453
|
const mut_arr: number[] = [1, 2];
|
|
454
454
|
|
|
455
|
-
assert.isTrue(
|
|
455
|
+
assert.isTrue(isFixedLengthTuple(mut_arr, 2));
|
|
456
456
|
|
|
457
|
-
if (
|
|
457
|
+
if (isFixedLengthTuple(mut_arr, 2)) {
|
|
458
458
|
// transformer-ignore-next-line
|
|
459
|
-
expectType<typeof mut_arr, number[] &
|
|
459
|
+
expectType<typeof mut_arr, number[] & FixedLengthTuple<2, number>>('=');
|
|
460
460
|
}
|
|
461
461
|
|
|
462
|
-
assert.isFalse(
|
|
462
|
+
assert.isFalse(isFixedLengthTuple(mut_arr, 3));
|
|
463
463
|
});
|
|
464
464
|
|
|
465
465
|
test('should work with unknown readonly array type', () => {
|
|
466
466
|
const arr: readonly number[] = [1, 2] as const;
|
|
467
467
|
|
|
468
|
-
assert.isTrue(
|
|
468
|
+
assert.isTrue(isFixedLengthTuple(arr, 2));
|
|
469
469
|
|
|
470
|
-
if (
|
|
471
|
-
expectType<typeof arr,
|
|
470
|
+
if (isFixedLengthTuple(arr, 2)) {
|
|
471
|
+
expectType<typeof arr, FixedLengthTuple<2, number>>('=');
|
|
472
472
|
}
|
|
473
473
|
|
|
474
|
-
assert.isFalse(
|
|
474
|
+
assert.isFalse(isFixedLengthTuple(arr, 3));
|
|
475
475
|
});
|
|
476
476
|
|
|
477
477
|
test('should return true for arrays of exact length (additional)', () => {
|
|
478
|
-
assert.isTrue(
|
|
478
|
+
assert.isTrue(isFixedLengthTuple([1, 2, 3], 3));
|
|
479
479
|
|
|
480
|
-
assert.isTrue(
|
|
480
|
+
assert.isTrue(isFixedLengthTuple([], 0));
|
|
481
481
|
|
|
482
|
-
assert.isTrue(
|
|
482
|
+
assert.isTrue(isFixedLengthTuple(['a'], 1));
|
|
483
483
|
});
|
|
484
484
|
|
|
485
485
|
test('should return false for arrays of different length (additional)', () => {
|
|
486
|
-
assert.isFalse(
|
|
486
|
+
assert.isFalse(isFixedLengthTuple([1, 2, 3], 2));
|
|
487
487
|
|
|
488
|
-
assert.isFalse(
|
|
488
|
+
assert.isFalse(isFixedLengthTuple([1, 2, 3], 4));
|
|
489
489
|
|
|
490
|
-
assert.isFalse(
|
|
490
|
+
assert.isFalse(isFixedLengthTuple([], 1));
|
|
491
491
|
});
|
|
492
492
|
|
|
493
493
|
test('should work as type guard with exact length (additional)', () => {
|
|
494
494
|
const array: readonly number[] = [1, 2, 3] as const;
|
|
495
495
|
|
|
496
|
-
if (
|
|
497
|
-
expectType<typeof array,
|
|
496
|
+
if (isFixedLengthTuple(array, 3)) {
|
|
497
|
+
expectType<typeof array, FixedLengthTuple<3, number>>('=');
|
|
498
498
|
|
|
499
499
|
expect(array).toHaveLength(3);
|
|
500
500
|
}
|
|
501
501
|
});
|
|
502
502
|
});
|
|
503
503
|
|
|
504
|
-
describe(
|
|
504
|
+
describe(isMinLengthTuple, () => {
|
|
505
505
|
test('should return true if array length is greater than or equal to specified length', () => {
|
|
506
506
|
const arr = [1, 2, 3] as const;
|
|
507
507
|
|
|
508
|
-
assert.isTrue(
|
|
508
|
+
assert.isTrue(isMinLengthTuple(arr, 3));
|
|
509
509
|
|
|
510
|
-
if (
|
|
510
|
+
if (isMinLengthTuple(arr, 3)) {
|
|
511
511
|
expectType<typeof arr, readonly [1, 2, 3]>('=');
|
|
512
512
|
}
|
|
513
513
|
|
|
514
|
-
assert.isTrue(
|
|
514
|
+
assert.isTrue(isMinLengthTuple(arr, 2));
|
|
515
515
|
|
|
516
|
-
if (
|
|
516
|
+
if (isMinLengthTuple(arr, 2)) {
|
|
517
517
|
expectType<typeof arr, readonly [1, 2, 3]>('=');
|
|
518
518
|
}
|
|
519
519
|
});
|
|
@@ -521,15 +521,15 @@ describe('Arr validations', () => {
|
|
|
521
521
|
test('should return false if array length is less than specified length', () => {
|
|
522
522
|
const arr = [1, 2, 3] as const;
|
|
523
523
|
|
|
524
|
-
assert.isFalse(
|
|
524
|
+
assert.isFalse(isMinLengthTuple(arr, 4));
|
|
525
525
|
});
|
|
526
526
|
|
|
527
527
|
test('should return true for empty array and length 0', () => {
|
|
528
528
|
const arr = [] as const;
|
|
529
529
|
|
|
530
|
-
assert.isTrue(
|
|
530
|
+
assert.isTrue(isMinLengthTuple(arr, 0));
|
|
531
531
|
|
|
532
|
-
if (
|
|
532
|
+
if (isMinLengthTuple(arr, 0)) {
|
|
533
533
|
expectType<typeof arr, readonly []>('=');
|
|
534
534
|
}
|
|
535
535
|
});
|
|
@@ -537,71 +537,71 @@ describe('Arr validations', () => {
|
|
|
537
537
|
test('should return false for empty array and positive length', () => {
|
|
538
538
|
const arr = [] as const;
|
|
539
539
|
|
|
540
|
-
assert.isFalse(
|
|
540
|
+
assert.isFalse(isMinLengthTuple(arr, 1));
|
|
541
541
|
});
|
|
542
542
|
|
|
543
543
|
test('should work with unknown array type', () => {
|
|
544
544
|
const mut_arr: number[] = [1, 2];
|
|
545
545
|
|
|
546
|
-
assert.isTrue(
|
|
546
|
+
assert.isTrue(isMinLengthTuple(mut_arr, 2));
|
|
547
547
|
|
|
548
548
|
// transformer-ignore-next-line
|
|
549
|
-
expectType<typeof mut_arr, number[] &
|
|
549
|
+
expectType<typeof mut_arr, number[] & MinLengthTuple<2, number>>('=');
|
|
550
550
|
|
|
551
|
-
assert.isFalse(
|
|
551
|
+
assert.isFalse(isMinLengthTuple(mut_arr, 3));
|
|
552
552
|
});
|
|
553
553
|
|
|
554
554
|
test('should work with unknown array type 2', () => {
|
|
555
555
|
const mut_arr: number[] = [1, 2];
|
|
556
556
|
|
|
557
|
-
assert.isTrue(
|
|
557
|
+
assert.isTrue(isMinLengthTuple(mut_arr, 1));
|
|
558
558
|
|
|
559
559
|
// transformer-ignore-next-line
|
|
560
|
-
expectType<typeof mut_arr, number[] &
|
|
560
|
+
expectType<typeof mut_arr, number[] & MinLengthTuple<1, number>>('=');
|
|
561
561
|
|
|
562
|
-
assert.isFalse(
|
|
562
|
+
assert.isFalse(isMinLengthTuple(mut_arr, 3));
|
|
563
563
|
});
|
|
564
564
|
|
|
565
565
|
test('should return true for arrays of at least specified length (additional)', () => {
|
|
566
|
-
assert.isTrue(
|
|
566
|
+
assert.isTrue(isMinLengthTuple([1, 2, 3], 3));
|
|
567
567
|
|
|
568
|
-
assert.isTrue(
|
|
568
|
+
assert.isTrue(isMinLengthTuple([1, 2, 3], 2));
|
|
569
569
|
|
|
570
|
-
assert.isTrue(
|
|
570
|
+
assert.isTrue(isMinLengthTuple([1, 2, 3], 1));
|
|
571
571
|
|
|
572
|
-
assert.isTrue(
|
|
572
|
+
assert.isTrue(isMinLengthTuple([1, 2, 3], 0));
|
|
573
573
|
});
|
|
574
574
|
|
|
575
575
|
test('should return false for arrays shorter than specified length (additional)', () => {
|
|
576
|
-
assert.isFalse(
|
|
576
|
+
assert.isFalse(isMinLengthTuple([1, 2, 3], 4));
|
|
577
577
|
|
|
578
|
-
assert.isFalse(
|
|
578
|
+
assert.isFalse(isMinLengthTuple([], 1));
|
|
579
579
|
});
|
|
580
580
|
|
|
581
581
|
test('should work as type guard for at least length (additional)', () => {
|
|
582
582
|
const array: readonly number[] = [1, 2, 3] as const;
|
|
583
583
|
|
|
584
|
-
if (
|
|
585
|
-
expectType<typeof array,
|
|
584
|
+
if (isMinLengthTuple(array, 2)) {
|
|
585
|
+
expectType<typeof array, MinLengthTuple<2, number>>('=');
|
|
586
586
|
|
|
587
587
|
expect(array.length).toBeGreaterThanOrEqual(2);
|
|
588
588
|
}
|
|
589
589
|
});
|
|
590
590
|
});
|
|
591
591
|
|
|
592
|
-
describe(
|
|
592
|
+
describe(isMaxLengthTuple, () => {
|
|
593
593
|
test('should return true if array length is less than or equal to specified length', () => {
|
|
594
594
|
const arr = [1, 2, 3] as const;
|
|
595
595
|
|
|
596
|
-
assert.isTrue(
|
|
596
|
+
assert.isTrue(isMaxLengthTuple(arr, 3));
|
|
597
597
|
|
|
598
|
-
if (
|
|
598
|
+
if (isMaxLengthTuple(arr, 3)) {
|
|
599
599
|
expectType<typeof arr, readonly [1, 2, 3]>('=');
|
|
600
600
|
}
|
|
601
601
|
|
|
602
|
-
assert.isTrue(
|
|
602
|
+
assert.isTrue(isMaxLengthTuple(arr, 4));
|
|
603
603
|
|
|
604
|
-
if (
|
|
604
|
+
if (isMaxLengthTuple(arr, 4)) {
|
|
605
605
|
expectType<typeof arr, readonly [1, 2, 3]>('=');
|
|
606
606
|
}
|
|
607
607
|
});
|
|
@@ -609,15 +609,15 @@ describe('Arr validations', () => {
|
|
|
609
609
|
test('should return false if array length is greater than specified length', () => {
|
|
610
610
|
const arr = [1, 2, 3] as const;
|
|
611
611
|
|
|
612
|
-
assert.isFalse(
|
|
612
|
+
assert.isFalse(isMaxLengthTuple(arr, 2));
|
|
613
613
|
});
|
|
614
614
|
|
|
615
615
|
test('should return true for empty array and length 0', () => {
|
|
616
616
|
const arr = [] as const;
|
|
617
617
|
|
|
618
|
-
assert.isTrue(
|
|
618
|
+
assert.isTrue(isMaxLengthTuple(arr, 0));
|
|
619
619
|
|
|
620
|
-
if (
|
|
620
|
+
if (isMaxLengthTuple(arr, 0)) {
|
|
621
621
|
expectType<typeof arr, readonly []>('=');
|
|
622
622
|
}
|
|
623
623
|
});
|
|
@@ -625,58 +625,58 @@ describe('Arr validations', () => {
|
|
|
625
625
|
test('should return false for non-empty array and length 0', () => {
|
|
626
626
|
const arr = [1] as const;
|
|
627
627
|
|
|
628
|
-
assert.isFalse(
|
|
628
|
+
assert.isFalse(isMaxLengthTuple(arr, 0));
|
|
629
629
|
});
|
|
630
630
|
|
|
631
631
|
test('should work with unknown array type', () => {
|
|
632
632
|
const mut_arr: number[] = [1, 2];
|
|
633
633
|
|
|
634
|
-
assert.isTrue(
|
|
634
|
+
assert.isTrue(isMaxLengthTuple(mut_arr, 2));
|
|
635
635
|
|
|
636
636
|
// transformer-ignore-next-line
|
|
637
|
-
expectType<typeof mut_arr, number[] &
|
|
637
|
+
expectType<typeof mut_arr, number[] & MaxLengthTuple<2, number>>('=');
|
|
638
638
|
|
|
639
|
-
assert.isFalse(
|
|
639
|
+
assert.isFalse(isMaxLengthTuple(mut_arr, 1));
|
|
640
640
|
});
|
|
641
641
|
|
|
642
642
|
test('should return true for arrays of at most specified length (additional)', () => {
|
|
643
|
-
assert.isTrue(
|
|
643
|
+
assert.isTrue(isMaxLengthTuple([1, 2, 3], 3));
|
|
644
644
|
|
|
645
|
-
assert.isTrue(
|
|
645
|
+
assert.isTrue(isMaxLengthTuple([1, 2, 3], 4));
|
|
646
646
|
|
|
647
|
-
assert.isTrue(
|
|
647
|
+
assert.isTrue(isMaxLengthTuple([], 0));
|
|
648
648
|
});
|
|
649
649
|
|
|
650
650
|
test('should return false for arrays longer than specified length (additional)', () => {
|
|
651
|
-
assert.isFalse(
|
|
651
|
+
assert.isFalse(isMaxLengthTuple([1, 2, 3], 2));
|
|
652
652
|
|
|
653
|
-
assert.isFalse(
|
|
653
|
+
assert.isFalse(isMaxLengthTuple([1, 2, 3], 0));
|
|
654
654
|
});
|
|
655
655
|
|
|
656
656
|
test('should work as type guard for at most length (additional)', () => {
|
|
657
657
|
const array: readonly number[] = [1, 2] as const;
|
|
658
658
|
|
|
659
|
-
if (
|
|
660
|
-
expectType<typeof array,
|
|
659
|
+
if (isMaxLengthTuple(array, 3)) {
|
|
660
|
+
expectType<typeof array, MaxLengthTuple<3, number>>('=');
|
|
661
661
|
|
|
662
662
|
expect(array.length).toBeLessThanOrEqual(3);
|
|
663
663
|
}
|
|
664
664
|
});
|
|
665
665
|
});
|
|
666
666
|
|
|
667
|
-
describe(
|
|
667
|
+
describe(isBoundedLengthTuple, () => {
|
|
668
668
|
test('should return true if array length is within the specified range', () => {
|
|
669
669
|
const arr = [1, 2, 3] as const;
|
|
670
670
|
|
|
671
|
-
assert.isTrue(
|
|
671
|
+
assert.isTrue(isBoundedLengthTuple(arr, 1, 3));
|
|
672
672
|
|
|
673
|
-
if (
|
|
673
|
+
if (isBoundedLengthTuple(arr, 1, 3)) {
|
|
674
674
|
expectType<typeof arr, readonly [1, 2, 3]>('=');
|
|
675
675
|
}
|
|
676
676
|
|
|
677
|
-
assert.isTrue(
|
|
677
|
+
assert.isTrue(isBoundedLengthTuple(arr, 3, 5));
|
|
678
678
|
|
|
679
|
-
if (
|
|
679
|
+
if (isBoundedLengthTuple(arr, 3, 5)) {
|
|
680
680
|
expectType<typeof arr, readonly [1, 2, 3]>('=');
|
|
681
681
|
}
|
|
682
682
|
});
|
|
@@ -684,21 +684,21 @@ describe('Arr validations', () => {
|
|
|
684
684
|
test('should return false if array length is below the specified range', () => {
|
|
685
685
|
const arr = [1, 2, 3] as const;
|
|
686
686
|
|
|
687
|
-
assert.isFalse(
|
|
687
|
+
assert.isFalse(isBoundedLengthTuple(arr, 4, 5));
|
|
688
688
|
});
|
|
689
689
|
|
|
690
690
|
test('should return false if array length is above the specified range', () => {
|
|
691
691
|
const arr = [1, 2, 3] as const;
|
|
692
692
|
|
|
693
|
-
assert.isFalse(
|
|
693
|
+
assert.isFalse(isBoundedLengthTuple(arr, 0, 2));
|
|
694
694
|
});
|
|
695
695
|
|
|
696
696
|
test('should return true for empty array and range including 0', () => {
|
|
697
697
|
const arr = [] as const;
|
|
698
698
|
|
|
699
|
-
assert.isTrue(
|
|
699
|
+
assert.isTrue(isBoundedLengthTuple(arr, 0, 2));
|
|
700
700
|
|
|
701
|
-
if (
|
|
701
|
+
if (isBoundedLengthTuple(arr, 0, 2)) {
|
|
702
702
|
expectType<typeof arr, readonly []>('=');
|
|
703
703
|
}
|
|
704
704
|
});
|
|
@@ -706,33 +706,35 @@ describe('Arr validations', () => {
|
|
|
706
706
|
test('should work with unknown array type', () => {
|
|
707
707
|
const mut_arr: number[] = [1, 2];
|
|
708
708
|
|
|
709
|
-
assert.isTrue(
|
|
709
|
+
assert.isTrue(isBoundedLengthTuple(mut_arr, 1, 3));
|
|
710
710
|
|
|
711
711
|
// transformer-ignore-next-line
|
|
712
|
-
expectType<typeof mut_arr, number[] &
|
|
712
|
+
expectType<typeof mut_arr, number[] & BoundedLengthTuple<1, 3, number>>(
|
|
713
|
+
'=',
|
|
714
|
+
);
|
|
713
715
|
|
|
714
|
-
assert.isFalse(
|
|
716
|
+
assert.isFalse(isBoundedLengthTuple(mut_arr, 3, 5));
|
|
715
717
|
});
|
|
716
718
|
|
|
717
719
|
test('should return true for arrays within specified range (additional)', () => {
|
|
718
|
-
assert.isTrue(
|
|
720
|
+
assert.isTrue(isBoundedLengthTuple([1, 2, 3], 1, 3));
|
|
719
721
|
|
|
720
|
-
assert.isTrue(
|
|
722
|
+
assert.isTrue(isBoundedLengthTuple([1, 2, 3], 3, 3));
|
|
721
723
|
|
|
722
|
-
assert.isTrue(
|
|
724
|
+
assert.isTrue(isBoundedLengthTuple([], 0, 0));
|
|
723
725
|
});
|
|
724
726
|
|
|
725
727
|
test('should return false for arrays outside specified range (additional)', () => {
|
|
726
|
-
assert.isFalse(
|
|
728
|
+
assert.isFalse(isBoundedLengthTuple([1, 2, 3], 4, 5));
|
|
727
729
|
|
|
728
|
-
assert.isFalse(
|
|
730
|
+
assert.isFalse(isBoundedLengthTuple([1, 2, 3], 0, 2));
|
|
729
731
|
});
|
|
730
732
|
|
|
731
733
|
test('should work as type guard for bounded length (additional)', () => {
|
|
732
734
|
const array: readonly number[] = [1, 2] as const;
|
|
733
735
|
|
|
734
|
-
if (
|
|
735
|
-
expectType<typeof array,
|
|
736
|
+
if (isBoundedLengthTuple(array, 1, 3)) {
|
|
737
|
+
expectType<typeof array, BoundedLengthTuple<1, 3, number>>('=');
|
|
736
738
|
|
|
737
739
|
expect(array.length).toBeGreaterThanOrEqual(1);
|
|
738
740
|
|
|
@@ -586,7 +586,7 @@ describe('Queue test', () => {
|
|
|
586
586
|
for (const _i of range(asUint32(1000))) {
|
|
587
587
|
// Randomly decide to enqueue or dequeue
|
|
588
588
|
const shouldEnqueue =
|
|
589
|
-
Arr.
|
|
589
|
+
Arr.isFixedLengthTuple(mut_expected, 0) || Math.random() < 0.6;
|
|
590
590
|
|
|
591
591
|
if (shouldEnqueue) {
|
|
592
592
|
mut_counter += 1;
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type BoundedLengthArray,
|
|
3
|
+
type FixedLengthArray,
|
|
4
|
+
type MaxLengthArray,
|
|
5
|
+
type MinLengthArray,
|
|
6
|
+
type SupportedLength,
|
|
7
|
+
} from 'ts-type-forge';
|
|
8
|
+
import {
|
|
9
|
+
isBoundedLengthArray,
|
|
10
|
+
isFixedLengthArray,
|
|
11
|
+
isMaxLengthArray,
|
|
12
|
+
isMinLengthArray,
|
|
13
|
+
} from './is-length-bounded-array.mjs';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Casts an array to `FixedLengthArray<Length, E>` after checking that it has
|
|
17
|
+
* exactly `length` elements.
|
|
18
|
+
*
|
|
19
|
+
* Use this instead of writing `xs as unknown as FixedLengthArray<N, E>`: the
|
|
20
|
+
* length is verified at runtime, and the original array type (e.g. tuple
|
|
21
|
+
* types) is preserved via intersection, so the result also benefits from the
|
|
22
|
+
* structural tuple prefix (in-range indexed access without `undefined` under
|
|
23
|
+
* `noUncheckedIndexedAccess`).
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
*
|
|
27
|
+
* ```ts
|
|
28
|
+
* const rgb = asFixedLengthArray([255, 128, 0], 3);
|
|
29
|
+
*
|
|
30
|
+
* const atMost5: MaxLengthArray<5, number> = rgb; // OK (3 <= 5)
|
|
31
|
+
* const red: number = rgb[0]; // OK — no `undefined`
|
|
32
|
+
*
|
|
33
|
+
* // asFixedLengthArray([255, 128], 3); // throws TypeError
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* @template Xs - The input array type (tuple types are preserved).
|
|
37
|
+
* @template Length - The exact number of elements.
|
|
38
|
+
* @param xs - The array to cast.
|
|
39
|
+
* @param length - The exact number of elements.
|
|
40
|
+
* @returns `xs` typed as `FixedLengthArray<Length, Xs[number]> & Xs`.
|
|
41
|
+
* @throws {TypeError} If `xs.length !== length`.
|
|
42
|
+
*/
|
|
43
|
+
export const asFixedLengthArray = <
|
|
44
|
+
Xs extends readonly unknown[],
|
|
45
|
+
Length extends SupportedLength,
|
|
46
|
+
>(
|
|
47
|
+
xs: Xs,
|
|
48
|
+
length: Length,
|
|
49
|
+
): FixedLengthArray<Length, Xs[number]> & Xs => {
|
|
50
|
+
if (!isFixedLengthArray(xs, length)) {
|
|
51
|
+
throw new TypeError(
|
|
52
|
+
`Expected an array of length ${length}, got an array of length ${xs.length}`,
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return xs;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Casts an array to `MinLengthArray<MinLength, E>` after checking that it has
|
|
61
|
+
* at least `minLength` elements.
|
|
62
|
+
*
|
|
63
|
+
* Use this instead of writing `xs as unknown as MinLengthArray<N, E>`: the
|
|
64
|
+
* length is verified at runtime, and the original array type (e.g. tuple
|
|
65
|
+
* types) is preserved via intersection, so the result also benefits from the
|
|
66
|
+
* structural tuple prefix (indexed access below `min(N, 10)` without
|
|
67
|
+
* `undefined` under `noUncheckedIndexedAccess`).
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
*
|
|
71
|
+
* ```ts
|
|
72
|
+
* const history = asMinLengthArray([0, 1, 2, 3], 3);
|
|
73
|
+
*
|
|
74
|
+
* const nonEmpty: MinLengthArray<1, number> = history; // OK (3 >= 1)
|
|
75
|
+
* const first: number = history[0]; // OK — no `undefined`
|
|
76
|
+
*
|
|
77
|
+
* // asMinLengthArray([0], 3); // throws TypeError
|
|
78
|
+
* ```
|
|
79
|
+
*
|
|
80
|
+
* @template Xs - The input array type (tuple types are preserved).
|
|
81
|
+
* @template MinLength - The minimum number of elements (inclusive).
|
|
82
|
+
* @param xs - The array to cast.
|
|
83
|
+
* @param minLength - The minimum number of elements (inclusive).
|
|
84
|
+
* @returns `xs` typed as `MinLengthArray<MinLength, Xs[number]> & Xs`.
|
|
85
|
+
* @throws {TypeError} If `xs.length < minLength`.
|
|
86
|
+
*/
|
|
87
|
+
export const asMinLengthArray = <
|
|
88
|
+
Xs extends readonly unknown[],
|
|
89
|
+
MinLength extends SupportedLength,
|
|
90
|
+
>(
|
|
91
|
+
xs: Xs,
|
|
92
|
+
minLength: MinLength,
|
|
93
|
+
): MinLengthArray<MinLength, Xs[number]> & Xs => {
|
|
94
|
+
if (!isMinLengthArray(xs, minLength)) {
|
|
95
|
+
throw new TypeError(
|
|
96
|
+
`Expected an array of length >= ${minLength}, got an array of length ${xs.length}`,
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return xs;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Casts an array to `MaxLengthArray<MaxLength, E>` after checking that it has
|
|
105
|
+
* at most `maxLength` elements.
|
|
106
|
+
*
|
|
107
|
+
* Use this instead of writing `xs as unknown as MaxLengthArray<N, E>`: the
|
|
108
|
+
* length is verified at runtime, and the original array type (e.g. tuple
|
|
109
|
+
* types) is preserved via intersection.
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
*
|
|
113
|
+
* ```ts
|
|
114
|
+
* const tags = asMaxLengthArray(['a', 'b', 'c'], 8);
|
|
115
|
+
*
|
|
116
|
+
* const relaxed: MaxLengthArray<16, string> = tags; // OK (8 <= 16)
|
|
117
|
+
*
|
|
118
|
+
* // asMaxLengthArray(['a', 'b', 'c'], 2); // throws TypeError
|
|
119
|
+
* ```
|
|
120
|
+
*
|
|
121
|
+
* @template Xs - The input array type (tuple types are preserved).
|
|
122
|
+
* @template MaxLength - The maximum number of elements (inclusive).
|
|
123
|
+
* @param xs - The array to cast.
|
|
124
|
+
* @param maxLength - The maximum number of elements (inclusive).
|
|
125
|
+
* @returns `xs` typed as `MaxLengthArray<MaxLength, Xs[number]> & Xs`.
|
|
126
|
+
* @throws {TypeError} If `xs.length > maxLength`.
|
|
127
|
+
*/
|
|
128
|
+
export const asMaxLengthArray = <
|
|
129
|
+
Xs extends readonly unknown[],
|
|
130
|
+
MaxLength extends SupportedLength,
|
|
131
|
+
>(
|
|
132
|
+
xs: Xs,
|
|
133
|
+
maxLength: MaxLength,
|
|
134
|
+
): MaxLengthArray<MaxLength, Xs[number]> & Xs => {
|
|
135
|
+
if (!isMaxLengthArray(xs, maxLength)) {
|
|
136
|
+
throw new TypeError(
|
|
137
|
+
`Expected an array of length <= ${maxLength}, got an array of length ${xs.length}`,
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return xs;
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Casts an array to `BoundedLengthArray<MinLength, MaxLength, E>` after
|
|
146
|
+
* checking that its length is within the inclusive range
|
|
147
|
+
* `[minLength, maxLength]`.
|
|
148
|
+
*
|
|
149
|
+
* Use this instead of writing
|
|
150
|
+
* `xs as unknown as BoundedLengthArray<Min, Max, E>`: the length is verified
|
|
151
|
+
* at runtime, and the original array type (e.g. tuple types) is preserved via
|
|
152
|
+
* intersection.
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
*
|
|
156
|
+
* ```ts
|
|
157
|
+
* const selection = asBoundedLengthArray([1, 2, 3], 1, 5);
|
|
158
|
+
*
|
|
159
|
+
* const relaxed: BoundedLengthArray<0, 100, number> = selection; // OK
|
|
160
|
+
*
|
|
161
|
+
* // asBoundedLengthArray([], 1, 5); // throws TypeError
|
|
162
|
+
* ```
|
|
163
|
+
*
|
|
164
|
+
* @template Xs - The input array type (tuple types are preserved).
|
|
165
|
+
* @template MinLength - The minimum number of elements (inclusive).
|
|
166
|
+
* @template MaxLength - The maximum number of elements (inclusive).
|
|
167
|
+
* @param xs - The array to cast.
|
|
168
|
+
* @param minLength - The minimum number of elements (inclusive).
|
|
169
|
+
* @param maxLength - The maximum number of elements (inclusive).
|
|
170
|
+
* @returns `xs` typed as
|
|
171
|
+
* `BoundedLengthArray<MinLength, MaxLength, Xs[number]> & Xs`.
|
|
172
|
+
* @throws {TypeError} If `xs.length < minLength || xs.length > maxLength`.
|
|
173
|
+
*/
|
|
174
|
+
export const asBoundedLengthArray = <
|
|
175
|
+
Xs extends readonly unknown[],
|
|
176
|
+
MinLength extends SupportedLength,
|
|
177
|
+
MaxLength extends SupportedLength,
|
|
178
|
+
>(
|
|
179
|
+
xs: Xs,
|
|
180
|
+
minLength: MinLength,
|
|
181
|
+
maxLength: MaxLength,
|
|
182
|
+
): BoundedLengthArray<MinLength, MaxLength, Xs[number]> & Xs => {
|
|
183
|
+
if (!isBoundedLengthArray(xs, minLength, maxLength)) {
|
|
184
|
+
throw new TypeError(
|
|
185
|
+
`Expected an array of length in [${minLength}, ${maxLength}], got an array of length ${xs.length}`,
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return xs;
|
|
190
|
+
};
|