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.
Files changed (50) hide show
  1. package/README.md +1 -1
  2. package/dist/array/impl/array-utils-creation.d.mts +4 -4
  3. package/dist/array/impl/array-utils-creation.d.mts.map +1 -1
  4. package/dist/array/impl/array-utils-creation.mjs.map +1 -1
  5. package/dist/array/impl/array-utils-modification.d.mts +7 -7
  6. package/dist/array/impl/array-utils-modification.d.mts.map +1 -1
  7. package/dist/array/impl/array-utils-modification.mjs.map +1 -1
  8. package/dist/array/impl/array-utils-transformation.d.mts +4 -4
  9. package/dist/array/impl/array-utils-transformation.d.mts.map +1 -1
  10. package/dist/array/impl/array-utils-transformation.mjs.map +1 -1
  11. package/dist/array/impl/array-utils-validation.d.mts +17 -17
  12. package/dist/array/impl/array-utils-validation.d.mts.map +1 -1
  13. package/dist/array/impl/array-utils-validation.mjs +5 -5
  14. package/dist/array/impl/array-utils-validation.mjs.map +1 -1
  15. package/dist/array/impl/index.mjs +1 -1
  16. package/dist/entry-point.mjs +2 -0
  17. package/dist/entry-point.mjs.map +1 -1
  18. package/dist/guard/as-length-bounded-array.d.mts +117 -0
  19. package/dist/guard/as-length-bounded-array.d.mts.map +1 -0
  20. package/dist/guard/as-length-bounded-array.mjs +37 -0
  21. package/dist/guard/as-length-bounded-array.mjs.map +1 -0
  22. package/dist/guard/index.d.mts +2 -0
  23. package/dist/guard/index.d.mts.map +1 -1
  24. package/dist/guard/index.mjs +2 -0
  25. package/dist/guard/index.mjs.map +1 -1
  26. package/dist/guard/is-length-bounded-array.d.mts +159 -0
  27. package/dist/guard/is-length-bounded-array.d.mts.map +1 -0
  28. package/dist/guard/is-length-bounded-array.mjs +7 -0
  29. package/dist/guard/is-length-bounded-array.mjs.map +1 -0
  30. package/dist/guard/is-length-bounded-string.d.mts +5 -6
  31. package/dist/guard/is-length-bounded-string.d.mts.map +1 -1
  32. package/dist/guard/is-length-bounded-string.mjs.map +1 -1
  33. package/dist/index.mjs +2 -0
  34. package/dist/index.mjs.map +1 -1
  35. package/package.json +7 -7
  36. package/src/array/impl/array-utils-creation.mts +3 -3
  37. package/src/array/impl/array-utils-modification.mts +7 -7
  38. package/src/array/impl/array-utils-modification.test.mts +4 -4
  39. package/src/array/impl/array-utils-transformation.mts +4 -4
  40. package/src/array/impl/array-utils-transformation.test.mts +7 -7
  41. package/src/array/impl/array-utils-validation.mts +24 -24
  42. package/src/array/impl/array-utils-validation.test.mts +94 -92
  43. package/src/collections/queue.test.mts +1 -1
  44. package/src/guard/as-length-bounded-array.mts +190 -0
  45. package/src/guard/as-length-bounded-array.test.mts +118 -0
  46. package/src/guard/index.mts +2 -0
  47. package/src/guard/is-length-bounded-array.mts +195 -0
  48. package/src/guard/is-length-bounded-array.test.mts +169 -0
  49. package/src/guard/is-length-bounded-string.mts +6 -6
  50. package/src/object/object.test.mts +3 -3
@@ -1,19 +1,19 @@
1
1
  import {
2
- type ArrayAtLeastLen,
3
- type ArrayAtMostLen,
4
- type ArrayBoundedLen,
5
- type ArrayOfLength,
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
- isArrayAtLeastLength,
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(isArrayOfLength, () => {
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(isArrayOfLength(arr, 3));
423
+ assert.isTrue(isFixedLengthTuple(arr, 3));
424
424
 
425
- if (isArrayOfLength(arr, 3)) {
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(isArrayOfLength(arr, 2));
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(isArrayOfLength(arr, 0));
439
+ assert.isTrue(isFixedLengthTuple(arr, 0));
440
440
 
441
- if (isArrayOfLength(arr, 0)) {
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(isArrayOfLength(arr, 0));
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(isArrayOfLength(mut_arr, 2));
455
+ assert.isTrue(isFixedLengthTuple(mut_arr, 2));
456
456
 
457
- if (isArrayOfLength(mut_arr, 2)) {
457
+ if (isFixedLengthTuple(mut_arr, 2)) {
458
458
  // transformer-ignore-next-line
459
- expectType<typeof mut_arr, number[] & ArrayOfLength<2, number>>('=');
459
+ expectType<typeof mut_arr, number[] & FixedLengthTuple<2, number>>('=');
460
460
  }
461
461
 
462
- assert.isFalse(isArrayOfLength(mut_arr, 3));
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(isArrayOfLength(arr, 2));
468
+ assert.isTrue(isFixedLengthTuple(arr, 2));
469
469
 
470
- if (isArrayOfLength(arr, 2)) {
471
- expectType<typeof arr, ArrayOfLength<2, number>>('=');
470
+ if (isFixedLengthTuple(arr, 2)) {
471
+ expectType<typeof arr, FixedLengthTuple<2, number>>('=');
472
472
  }
473
473
 
474
- assert.isFalse(isArrayOfLength(arr, 3));
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(isArrayOfLength([1, 2, 3], 3));
478
+ assert.isTrue(isFixedLengthTuple([1, 2, 3], 3));
479
479
 
480
- assert.isTrue(isArrayOfLength([], 0));
480
+ assert.isTrue(isFixedLengthTuple([], 0));
481
481
 
482
- assert.isTrue(isArrayOfLength(['a'], 1));
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(isArrayOfLength([1, 2, 3], 2));
486
+ assert.isFalse(isFixedLengthTuple([1, 2, 3], 2));
487
487
 
488
- assert.isFalse(isArrayOfLength([1, 2, 3], 4));
488
+ assert.isFalse(isFixedLengthTuple([1, 2, 3], 4));
489
489
 
490
- assert.isFalse(isArrayOfLength([], 1));
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 (isArrayOfLength(array, 3)) {
497
- expectType<typeof array, ArrayOfLength<3, number>>('=');
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(isArrayAtLeastLength, () => {
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(isArrayAtLeastLength(arr, 3));
508
+ assert.isTrue(isMinLengthTuple(arr, 3));
509
509
 
510
- if (isArrayAtLeastLength(arr, 3)) {
510
+ if (isMinLengthTuple(arr, 3)) {
511
511
  expectType<typeof arr, readonly [1, 2, 3]>('=');
512
512
  }
513
513
 
514
- assert.isTrue(isArrayAtLeastLength(arr, 2));
514
+ assert.isTrue(isMinLengthTuple(arr, 2));
515
515
 
516
- if (isArrayAtLeastLength(arr, 2)) {
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(isArrayAtLeastLength(arr, 4));
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(isArrayAtLeastLength(arr, 0));
530
+ assert.isTrue(isMinLengthTuple(arr, 0));
531
531
 
532
- if (isArrayAtLeastLength(arr, 0)) {
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(isArrayAtLeastLength(arr, 1));
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(isArrayAtLeastLength(mut_arr, 2));
546
+ assert.isTrue(isMinLengthTuple(mut_arr, 2));
547
547
 
548
548
  // transformer-ignore-next-line
549
- expectType<typeof mut_arr, number[] & ArrayAtLeastLen<2, number>>('=');
549
+ expectType<typeof mut_arr, number[] & MinLengthTuple<2, number>>('=');
550
550
 
551
- assert.isFalse(isArrayAtLeastLength(mut_arr, 3));
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(isArrayAtLeastLength(mut_arr, 1));
557
+ assert.isTrue(isMinLengthTuple(mut_arr, 1));
558
558
 
559
559
  // transformer-ignore-next-line
560
- expectType<typeof mut_arr, number[] & ArrayAtLeastLen<1, number>>('=');
560
+ expectType<typeof mut_arr, number[] & MinLengthTuple<1, number>>('=');
561
561
 
562
- assert.isFalse(isArrayAtLeastLength(mut_arr, 3));
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(isArrayAtLeastLength([1, 2, 3], 3));
566
+ assert.isTrue(isMinLengthTuple([1, 2, 3], 3));
567
567
 
568
- assert.isTrue(isArrayAtLeastLength([1, 2, 3], 2));
568
+ assert.isTrue(isMinLengthTuple([1, 2, 3], 2));
569
569
 
570
- assert.isTrue(isArrayAtLeastLength([1, 2, 3], 1));
570
+ assert.isTrue(isMinLengthTuple([1, 2, 3], 1));
571
571
 
572
- assert.isTrue(isArrayAtLeastLength([1, 2, 3], 0));
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(isArrayAtLeastLength([1, 2, 3], 4));
576
+ assert.isFalse(isMinLengthTuple([1, 2, 3], 4));
577
577
 
578
- assert.isFalse(isArrayAtLeastLength([], 1));
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 (isArrayAtLeastLength(array, 2)) {
585
- expectType<typeof array, ArrayAtLeastLen<2, number>>('=');
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(isArrayAtMostLength, () => {
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(isArrayAtMostLength(arr, 3));
596
+ assert.isTrue(isMaxLengthTuple(arr, 3));
597
597
 
598
- if (isArrayAtMostLength(arr, 3)) {
598
+ if (isMaxLengthTuple(arr, 3)) {
599
599
  expectType<typeof arr, readonly [1, 2, 3]>('=');
600
600
  }
601
601
 
602
- assert.isTrue(isArrayAtMostLength(arr, 4));
602
+ assert.isTrue(isMaxLengthTuple(arr, 4));
603
603
 
604
- if (isArrayAtMostLength(arr, 4)) {
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(isArrayAtMostLength(arr, 2));
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(isArrayAtMostLength(arr, 0));
618
+ assert.isTrue(isMaxLengthTuple(arr, 0));
619
619
 
620
- if (isArrayAtMostLength(arr, 0)) {
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(isArrayAtMostLength(arr, 0));
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(isArrayAtMostLength(mut_arr, 2));
634
+ assert.isTrue(isMaxLengthTuple(mut_arr, 2));
635
635
 
636
636
  // transformer-ignore-next-line
637
- expectType<typeof mut_arr, number[] & ArrayAtMostLen<2, number>>('=');
637
+ expectType<typeof mut_arr, number[] & MaxLengthTuple<2, number>>('=');
638
638
 
639
- assert.isFalse(isArrayAtMostLength(mut_arr, 1));
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(isArrayAtMostLength([1, 2, 3], 3));
643
+ assert.isTrue(isMaxLengthTuple([1, 2, 3], 3));
644
644
 
645
- assert.isTrue(isArrayAtMostLength([1, 2, 3], 4));
645
+ assert.isTrue(isMaxLengthTuple([1, 2, 3], 4));
646
646
 
647
- assert.isTrue(isArrayAtMostLength([], 0));
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(isArrayAtMostLength([1, 2, 3], 2));
651
+ assert.isFalse(isMaxLengthTuple([1, 2, 3], 2));
652
652
 
653
- assert.isFalse(isArrayAtMostLength([1, 2, 3], 0));
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 (isArrayAtMostLength(array, 3)) {
660
- expectType<typeof array, ArrayAtMostLen<3, number>>('=');
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(isArrayBoundedLength, () => {
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(isArrayBoundedLength(arr, 1, 3));
671
+ assert.isTrue(isBoundedLengthTuple(arr, 1, 3));
672
672
 
673
- if (isArrayBoundedLength(arr, 1, 3)) {
673
+ if (isBoundedLengthTuple(arr, 1, 3)) {
674
674
  expectType<typeof arr, readonly [1, 2, 3]>('=');
675
675
  }
676
676
 
677
- assert.isTrue(isArrayBoundedLength(arr, 3, 5));
677
+ assert.isTrue(isBoundedLengthTuple(arr, 3, 5));
678
678
 
679
- if (isArrayBoundedLength(arr, 3, 5)) {
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(isArrayBoundedLength(arr, 4, 5));
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(isArrayBoundedLength(arr, 0, 2));
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(isArrayBoundedLength(arr, 0, 2));
699
+ assert.isTrue(isBoundedLengthTuple(arr, 0, 2));
700
700
 
701
- if (isArrayBoundedLength(arr, 0, 2)) {
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(isArrayBoundedLength(mut_arr, 1, 3));
709
+ assert.isTrue(isBoundedLengthTuple(mut_arr, 1, 3));
710
710
 
711
711
  // transformer-ignore-next-line
712
- expectType<typeof mut_arr, number[] & ArrayBoundedLen<1, 3, number>>('=');
712
+ expectType<typeof mut_arr, number[] & BoundedLengthTuple<1, 3, number>>(
713
+ '=',
714
+ );
713
715
 
714
- assert.isFalse(isArrayBoundedLength(mut_arr, 3, 5));
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(isArrayBoundedLength([1, 2, 3], 1, 3));
720
+ assert.isTrue(isBoundedLengthTuple([1, 2, 3], 1, 3));
719
721
 
720
- assert.isTrue(isArrayBoundedLength([1, 2, 3], 3, 3));
722
+ assert.isTrue(isBoundedLengthTuple([1, 2, 3], 3, 3));
721
723
 
722
- assert.isTrue(isArrayBoundedLength([], 0, 0));
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(isArrayBoundedLength([1, 2, 3], 4, 5));
728
+ assert.isFalse(isBoundedLengthTuple([1, 2, 3], 4, 5));
727
729
 
728
- assert.isFalse(isArrayBoundedLength([1, 2, 3], 0, 2));
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 (isArrayBoundedLength(array, 1, 3)) {
735
- expectType<typeof array, ArrayBoundedLen<1, 3, number>>('=');
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.isArrayOfLength(mut_expected, 0) || Math.random() < 0.6;
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
+ };