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.
Files changed (93) hide show
  1. package/README.md +4 -3
  2. package/dist/array/impl/array-utils-creation.d.mts +2 -2
  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-length-bounded-array-cast.d.mts +56 -29
  6. package/dist/array/impl/array-utils-length-bounded-array-cast.d.mts.map +1 -1
  7. package/dist/array/impl/array-utils-length-bounded-array-cast.mjs +23 -15
  8. package/dist/array/impl/array-utils-length-bounded-array-cast.mjs.map +1 -1
  9. package/dist/array/impl/array-utils-length-bounded-array-guard.d.mts +126 -28
  10. package/dist/array/impl/array-utils-length-bounded-array-guard.d.mts.map +1 -1
  11. package/dist/array/impl/array-utils-length-bounded-array-guard.mjs +39 -5
  12. package/dist/array/impl/array-utils-length-bounded-array-guard.mjs.map +1 -1
  13. package/dist/array/impl/array-utils-length-bounded-tuple-cast.d.mts +167 -0
  14. package/dist/array/impl/array-utils-length-bounded-tuple-cast.d.mts.map +1 -0
  15. package/dist/array/impl/array-utils-length-bounded-tuple-cast.mjs +87 -0
  16. package/dist/array/impl/array-utils-length-bounded-tuple-cast.mjs.map +1 -0
  17. package/dist/array/impl/array-utils-length-bounded-tuple-guard.d.mts +135 -0
  18. package/dist/array/impl/array-utils-length-bounded-tuple-guard.d.mts.map +1 -0
  19. package/dist/array/impl/array-utils-length-bounded-tuple-guard.mjs +41 -0
  20. package/dist/array/impl/array-utils-length-bounded-tuple-guard.mjs.map +1 -0
  21. package/dist/array/impl/array-utils-modification.d.mts +45 -18
  22. package/dist/array/impl/array-utils-modification.d.mts.map +1 -1
  23. package/dist/array/impl/array-utils-modification.mjs.map +1 -1
  24. package/dist/array/impl/array-utils-reducing-value.d.mts +3 -3
  25. package/dist/array/impl/array-utils-reducing-value.d.mts.map +1 -1
  26. package/dist/array/impl/array-utils-reducing-value.mjs +1 -1
  27. package/dist/array/impl/array-utils-reducing-value.mjs.map +1 -1
  28. package/dist/array/impl/array-utils-slice-clamped.d.mts.map +1 -1
  29. package/dist/array/impl/array-utils-slice-clamped.mjs.map +1 -1
  30. package/dist/array/impl/array-utils-slicing.d.mts +11 -11
  31. package/dist/array/impl/array-utils-slicing.d.mts.map +1 -1
  32. package/dist/array/impl/array-utils-slicing.mjs +1 -1
  33. package/dist/array/impl/array-utils-slicing.mjs.map +1 -1
  34. package/dist/array/impl/array-utils-transformation.d.mts +36 -19
  35. package/dist/array/impl/array-utils-transformation.d.mts.map +1 -1
  36. package/dist/array/impl/array-utils-transformation.mjs +2 -2
  37. package/dist/array/impl/array-utils-transformation.mjs.map +1 -1
  38. package/dist/array/impl/array-utils-validation.d.mts +2 -124
  39. package/dist/array/impl/array-utils-validation.d.mts.map +1 -1
  40. package/dist/array/impl/array-utils-validation.mjs +1 -7
  41. package/dist/array/impl/array-utils-validation.mjs.map +1 -1
  42. package/dist/array/impl/index.d.mts +2 -0
  43. package/dist/array/impl/index.d.mts.map +1 -1
  44. package/dist/array/impl/index.mjs +5 -3
  45. package/dist/array/impl/index.mjs.map +1 -1
  46. package/dist/collections/imap.d.mts +1 -1
  47. package/dist/collections/imap.mjs.map +1 -1
  48. package/dist/collections/iset-mapped.d.mts +2 -2
  49. package/dist/collections/iset-mapped.d.mts.map +1 -1
  50. package/dist/collections/iset-mapped.mjs.map +1 -1
  51. package/dist/collections/iset.d.mts +2 -2
  52. package/dist/collections/iset.d.mts.map +1 -1
  53. package/dist/collections/iset.mjs.map +1 -1
  54. package/dist/number/num-arithmetic-types.d.mts +2 -2
  55. package/dist/number/num-arithmetic-types.d.mts.map +1 -1
  56. package/dist/object/object.mjs +1 -1
  57. package/dist/string/str.d.mts +44 -44
  58. package/dist/string/str.d.mts.map +1 -1
  59. package/dist/string/str.mjs +17 -17
  60. package/dist/string/str.mjs.map +1 -1
  61. package/package.json +4 -5
  62. package/src/array/impl/array-utils-creation.mts +7 -3
  63. package/src/array/impl/array-utils-creation.test.mts +10 -8
  64. package/src/array/impl/array-utils-length-bounded-array-cast.mts +88 -50
  65. package/src/array/impl/array-utils-length-bounded-array-cast.test.mts +40 -13
  66. package/src/array/impl/array-utils-length-bounded-array-guard.mts +248 -39
  67. package/src/array/impl/array-utils-length-bounded-array-guard.test.mts +135 -24
  68. package/src/array/impl/array-utils-length-bounded-tuple-cast.mts +364 -0
  69. package/src/array/impl/array-utils-length-bounded-tuple-cast.test.mts +207 -0
  70. package/src/array/impl/array-utils-length-bounded-tuple-guard.mts +266 -0
  71. package/src/array/impl/array-utils-length-bounded-tuple-guard.test.mts +441 -0
  72. package/src/array/impl/array-utils-length-constraint-preservation.test.mts +287 -0
  73. package/src/array/impl/array-utils-modification.mts +84 -61
  74. package/src/array/impl/array-utils-modification.test.mts +145 -6
  75. package/src/array/impl/array-utils-reducing-value.mts +5 -5
  76. package/src/array/impl/array-utils-shape-invariants.test.mts +284 -0
  77. package/src/array/impl/array-utils-slice-clamped.mts +2 -1
  78. package/src/array/impl/array-utils-slicing.mts +65 -43
  79. package/src/array/impl/array-utils-slicing.test.mts +55 -0
  80. package/src/array/impl/array-utils-transformation.mts +91 -37
  81. package/src/array/impl/array-utils-transformation.test.mts +96 -23
  82. package/src/array/impl/array-utils-validation.mts +2 -162
  83. package/src/array/impl/array-utils-validation.test.mts +0 -371
  84. package/src/array/impl/index.mts +2 -0
  85. package/src/collections/imap.mts +1 -1
  86. package/src/collections/iset-mapped.mts +7 -3
  87. package/src/collections/iset.mts +7 -3
  88. package/src/collections/iset.test.mts +9 -6
  89. package/src/collections/queue.test.mts +1 -1
  90. package/src/number/num-arithmetic-types.mts +8 -4
  91. package/src/number/num.test.mts +2 -2
  92. package/src/string/str.mts +69 -69
  93. package/src/string/str.test.mts +40 -40
@@ -1,20 +1,8 @@
1
- import {
2
- type BoundedLengthTuple,
3
- type FixedLengthTuple,
4
- type MaxLengthTuple,
5
- type MinLengthTuple,
6
- } from 'ts-type-forge';
7
1
  import { expectType } from '../../expect-type.mjs';
8
2
  import {
9
3
  every,
10
4
  indexIsInRange,
11
5
  isArray,
12
- isBoundedLengthTuple,
13
- isEmpty,
14
- isFixedLengthTuple,
15
- isMaxLengthTuple,
16
- isMinLengthTuple,
17
- isNonEmpty,
18
6
  some,
19
7
  } from './array-utils-validation.mjs';
20
8
 
@@ -384,365 +372,6 @@ describe('Arr validations', () => {
384
372
  });
385
373
  });
386
374
 
387
- describe(isEmpty, () => {
388
- const xs = [1, 2, 3] as const;
389
-
390
- const result = isEmpty(xs);
391
-
392
- expectType<typeof result, boolean>('=');
393
-
394
- test('case 1', () => {
395
- assert.isFalse(result);
396
- });
397
-
398
- test('case 2', () => {
399
- assert.isTrue(isEmpty([]));
400
- });
401
- });
402
-
403
- describe(isNonEmpty, () => {
404
- const xs = [1, 2, 3] as const;
405
-
406
- const result = isNonEmpty(xs);
407
-
408
- expectType<typeof result, boolean>('=');
409
-
410
- test('case 1', () => {
411
- assert.isTrue(result);
412
- });
413
-
414
- test('case 2', () => {
415
- assert.isFalse(isNonEmpty([]));
416
- });
417
- });
418
-
419
- describe(isFixedLengthTuple, () => {
420
- test('should return true if array has specified length', () => {
421
- const arr = [1, 2, 3] as const;
422
-
423
- assert.isTrue(isFixedLengthTuple(arr, 3));
424
-
425
- if (isFixedLengthTuple(arr, 3)) {
426
- expectType<typeof arr, readonly [1, 2, 3]>('=');
427
- }
428
- });
429
-
430
- test('should return false if array does not have specified length', () => {
431
- const arr = [1, 2, 3] as const;
432
-
433
- assert.isFalse(isFixedLengthTuple(arr, 2));
434
- });
435
-
436
- test('should return true for empty array and length 0', () => {
437
- const arr = [] as const;
438
-
439
- assert.isTrue(isFixedLengthTuple(arr, 0));
440
-
441
- if (isFixedLengthTuple(arr, 0)) {
442
- expectType<typeof arr, readonly []>('=');
443
- }
444
- });
445
-
446
- test('should return false for non-empty array and length 0', () => {
447
- const arr = [1] as const;
448
-
449
- assert.isFalse(isFixedLengthTuple(arr, 0));
450
- });
451
-
452
- test('should work with unknown array type', () => {
453
- const mut_arr: number[] = [1, 2];
454
-
455
- assert.isTrue(isFixedLengthTuple(mut_arr, 2));
456
-
457
- if (isFixedLengthTuple(mut_arr, 2)) {
458
- // transformer-ignore-next-line
459
- expectType<typeof mut_arr, number[] & FixedLengthTuple<2, number>>('=');
460
- }
461
-
462
- assert.isFalse(isFixedLengthTuple(mut_arr, 3));
463
- });
464
-
465
- test('should work with unknown readonly array type', () => {
466
- const arr: readonly number[] = [1, 2] as const;
467
-
468
- assert.isTrue(isFixedLengthTuple(arr, 2));
469
-
470
- if (isFixedLengthTuple(arr, 2)) {
471
- expectType<typeof arr, FixedLengthTuple<2, number>>('=');
472
- }
473
-
474
- assert.isFalse(isFixedLengthTuple(arr, 3));
475
- });
476
-
477
- test('should return true for arrays of exact length (additional)', () => {
478
- assert.isTrue(isFixedLengthTuple([1, 2, 3], 3));
479
-
480
- assert.isTrue(isFixedLengthTuple([], 0));
481
-
482
- assert.isTrue(isFixedLengthTuple(['a'], 1));
483
- });
484
-
485
- test('should return false for arrays of different length (additional)', () => {
486
- assert.isFalse(isFixedLengthTuple([1, 2, 3], 2));
487
-
488
- assert.isFalse(isFixedLengthTuple([1, 2, 3], 4));
489
-
490
- assert.isFalse(isFixedLengthTuple([], 1));
491
- });
492
-
493
- test('should work as type guard with exact length (additional)', () => {
494
- const array: readonly number[] = [1, 2, 3] as const;
495
-
496
- if (isFixedLengthTuple(array, 3)) {
497
- expectType<typeof array, FixedLengthTuple<3, number>>('=');
498
-
499
- expect(array).toHaveLength(3);
500
- }
501
- });
502
- });
503
-
504
- describe(isMinLengthTuple, () => {
505
- test('should return true if array length is greater than or equal to specified length', () => {
506
- const arr = [1, 2, 3] as const;
507
-
508
- assert.isTrue(isMinLengthTuple(arr, 3));
509
-
510
- if (isMinLengthTuple(arr, 3)) {
511
- expectType<typeof arr, readonly [1, 2, 3]>('=');
512
- }
513
-
514
- assert.isTrue(isMinLengthTuple(arr, 2));
515
-
516
- if (isMinLengthTuple(arr, 2)) {
517
- expectType<typeof arr, readonly [1, 2, 3]>('=');
518
- }
519
- });
520
-
521
- test('should return false if array length is less than specified length', () => {
522
- const arr = [1, 2, 3] as const;
523
-
524
- assert.isFalse(isMinLengthTuple(arr, 4));
525
- });
526
-
527
- test('should return true for empty array and length 0', () => {
528
- const arr = [] as const;
529
-
530
- assert.isTrue(isMinLengthTuple(arr, 0));
531
-
532
- if (isMinLengthTuple(arr, 0)) {
533
- expectType<typeof arr, readonly []>('=');
534
- }
535
- });
536
-
537
- test('should return false for empty array and positive length', () => {
538
- const arr = [] as const;
539
-
540
- assert.isFalse(isMinLengthTuple(arr, 1));
541
- });
542
-
543
- test('should work with unknown array type', () => {
544
- const mut_arr: number[] = [1, 2];
545
-
546
- assert.isTrue(isMinLengthTuple(mut_arr, 2));
547
-
548
- // transformer-ignore-next-line
549
- expectType<typeof mut_arr, number[] & MinLengthTuple<2, number>>('=');
550
-
551
- assert.isFalse(isMinLengthTuple(mut_arr, 3));
552
- });
553
-
554
- test('should work with unknown array type 2', () => {
555
- const mut_arr: number[] = [1, 2];
556
-
557
- assert.isTrue(isMinLengthTuple(mut_arr, 1));
558
-
559
- // transformer-ignore-next-line
560
- expectType<typeof mut_arr, number[] & MinLengthTuple<1, number>>('=');
561
-
562
- assert.isFalse(isMinLengthTuple(mut_arr, 3));
563
- });
564
-
565
- test('should return true for arrays of at least specified length (additional)', () => {
566
- assert.isTrue(isMinLengthTuple([1, 2, 3], 3));
567
-
568
- assert.isTrue(isMinLengthTuple([1, 2, 3], 2));
569
-
570
- assert.isTrue(isMinLengthTuple([1, 2, 3], 1));
571
-
572
- assert.isTrue(isMinLengthTuple([1, 2, 3], 0));
573
- });
574
-
575
- test('should return false for arrays shorter than specified length (additional)', () => {
576
- assert.isFalse(isMinLengthTuple([1, 2, 3], 4));
577
-
578
- assert.isFalse(isMinLengthTuple([], 1));
579
- });
580
-
581
- test('should work as type guard for at least length (additional)', () => {
582
- const array: readonly number[] = [1, 2, 3] as const;
583
-
584
- if (isMinLengthTuple(array, 2)) {
585
- expectType<typeof array, MinLengthTuple<2, number>>('=');
586
-
587
- expect(array.length).toBeGreaterThanOrEqual(2);
588
- }
589
- });
590
- });
591
-
592
- describe(isMaxLengthTuple, () => {
593
- test('should return true if array length is less than or equal to specified length', () => {
594
- const arr = [1, 2, 3] as const;
595
-
596
- assert.isTrue(isMaxLengthTuple(arr, 3));
597
-
598
- if (isMaxLengthTuple(arr, 3)) {
599
- expectType<typeof arr, readonly [1, 2, 3]>('=');
600
- }
601
-
602
- assert.isTrue(isMaxLengthTuple(arr, 4));
603
-
604
- if (isMaxLengthTuple(arr, 4)) {
605
- expectType<typeof arr, readonly [1, 2, 3]>('=');
606
- }
607
- });
608
-
609
- test('should return false if array length is greater than specified length', () => {
610
- const arr = [1, 2, 3] as const;
611
-
612
- assert.isFalse(isMaxLengthTuple(arr, 2));
613
- });
614
-
615
- test('should return true for empty array and length 0', () => {
616
- const arr = [] as const;
617
-
618
- assert.isTrue(isMaxLengthTuple(arr, 0));
619
-
620
- if (isMaxLengthTuple(arr, 0)) {
621
- expectType<typeof arr, readonly []>('=');
622
- }
623
- });
624
-
625
- test('should return false for non-empty array and length 0', () => {
626
- const arr = [1] as const;
627
-
628
- assert.isFalse(isMaxLengthTuple(arr, 0));
629
- });
630
-
631
- test('should work with unknown array type', () => {
632
- const mut_arr: number[] = [1, 2];
633
-
634
- assert.isTrue(isMaxLengthTuple(mut_arr, 2));
635
-
636
- // transformer-ignore-next-line
637
- expectType<typeof mut_arr, number[] & MaxLengthTuple<2, number>>('=');
638
-
639
- assert.isFalse(isMaxLengthTuple(mut_arr, 1));
640
- });
641
-
642
- test('should return true for arrays of at most specified length (additional)', () => {
643
- assert.isTrue(isMaxLengthTuple([1, 2, 3], 3));
644
-
645
- assert.isTrue(isMaxLengthTuple([1, 2, 3], 4));
646
-
647
- assert.isTrue(isMaxLengthTuple([], 0));
648
- });
649
-
650
- test('should return false for arrays longer than specified length (additional)', () => {
651
- assert.isFalse(isMaxLengthTuple([1, 2, 3], 2));
652
-
653
- assert.isFalse(isMaxLengthTuple([1, 2, 3], 0));
654
- });
655
-
656
- test('should work as type guard for at most length (additional)', () => {
657
- const array: readonly number[] = [1, 2] as const;
658
-
659
- if (isMaxLengthTuple(array, 3)) {
660
- expectType<typeof array, MaxLengthTuple<3, number>>('=');
661
-
662
- expect(array.length).toBeLessThanOrEqual(3);
663
- }
664
- });
665
- });
666
-
667
- describe(isBoundedLengthTuple, () => {
668
- test('should return true if array length is within the specified range', () => {
669
- const arr = [1, 2, 3] as const;
670
-
671
- assert.isTrue(isBoundedLengthTuple(arr, 1, 3));
672
-
673
- if (isBoundedLengthTuple(arr, 1, 3)) {
674
- expectType<typeof arr, readonly [1, 2, 3]>('=');
675
- }
676
-
677
- assert.isTrue(isBoundedLengthTuple(arr, 3, 5));
678
-
679
- if (isBoundedLengthTuple(arr, 3, 5)) {
680
- expectType<typeof arr, readonly [1, 2, 3]>('=');
681
- }
682
- });
683
-
684
- test('should return false if array length is below the specified range', () => {
685
- const arr = [1, 2, 3] as const;
686
-
687
- assert.isFalse(isBoundedLengthTuple(arr, 4, 5));
688
- });
689
-
690
- test('should return false if array length is above the specified range', () => {
691
- const arr = [1, 2, 3] as const;
692
-
693
- assert.isFalse(isBoundedLengthTuple(arr, 0, 2));
694
- });
695
-
696
- test('should return true for empty array and range including 0', () => {
697
- const arr = [] as const;
698
-
699
- assert.isTrue(isBoundedLengthTuple(arr, 0, 2));
700
-
701
- if (isBoundedLengthTuple(arr, 0, 2)) {
702
- expectType<typeof arr, readonly []>('=');
703
- }
704
- });
705
-
706
- test('should work with unknown array type', () => {
707
- const mut_arr: number[] = [1, 2];
708
-
709
- assert.isTrue(isBoundedLengthTuple(mut_arr, 1, 3));
710
-
711
- // transformer-ignore-next-line
712
- expectType<typeof mut_arr, number[] & BoundedLengthTuple<1, 3, number>>(
713
- '=',
714
- );
715
-
716
- assert.isFalse(isBoundedLengthTuple(mut_arr, 3, 5));
717
- });
718
-
719
- test('should return true for arrays within specified range (additional)', () => {
720
- assert.isTrue(isBoundedLengthTuple([1, 2, 3], 1, 3));
721
-
722
- assert.isTrue(isBoundedLengthTuple([1, 2, 3], 3, 3));
723
-
724
- assert.isTrue(isBoundedLengthTuple([], 0, 0));
725
- });
726
-
727
- test('should return false for arrays outside specified range (additional)', () => {
728
- assert.isFalse(isBoundedLengthTuple([1, 2, 3], 4, 5));
729
-
730
- assert.isFalse(isBoundedLengthTuple([1, 2, 3], 0, 2));
731
- });
732
-
733
- test('should work as type guard for bounded length (additional)', () => {
734
- const array: readonly number[] = [1, 2] as const;
735
-
736
- if (isBoundedLengthTuple(array, 1, 3)) {
737
- expectType<typeof array, BoundedLengthTuple<1, 3, number>>('=');
738
-
739
- expect(array.length).toBeGreaterThanOrEqual(1);
740
-
741
- expect(array.length).toBeLessThanOrEqual(3);
742
- }
743
- });
744
- });
745
-
746
375
  describe(every, () => {
747
376
  test('should return true when all elements satisfy predicate', () => {
748
377
  const evens = [2, 4, 6, 8] as const;
@@ -3,6 +3,8 @@ export * from './array-utils-element-access.mjs';
3
3
  export * from './array-utils-iterators.mjs';
4
4
  export * from './array-utils-length-bounded-array-cast.mjs';
5
5
  export * from './array-utils-length-bounded-array-guard.mjs';
6
+ export * from './array-utils-length-bounded-tuple-cast.mjs';
7
+ export * from './array-utils-length-bounded-tuple-guard.mjs';
6
8
  export * from './array-utils-modification.mjs';
7
9
  export * from './array-utils-reducing-value.mjs';
8
10
  export * from './array-utils-search.mjs';
@@ -549,7 +549,7 @@ type IMapInterface<K extends MapSetKeyType, V> = Readonly<{
549
549
  * const entries = [
550
550
  * ['k1', 'v1'],
551
551
  * ['k2', 'v2'],
552
- * ] as const satisfies readonly (readonly [string, string])[];
552
+ * ] as const satisfies readonly FixedLengthTuple<2, string>[];
553
553
  *
554
554
  * const map = IMap.create(entries);
555
555
  *
@@ -1,5 +1,9 @@
1
1
  /* eslint-disable unicorn/prefer-iterator-to-array-at-end */
2
- import { type ReadonlyRecord, type WidenLiteral } from 'ts-type-forge';
2
+ import {
3
+ type FixedLengthTuple,
4
+ type ReadonlyRecord,
5
+ type WidenLiteral,
6
+ } from 'ts-type-forge';
3
7
  import { asUint32 } from '../number/index.mjs';
4
8
  import { type MapSetKeyType, type SizeType } from '../types.mjs';
5
9
 
@@ -788,7 +792,7 @@ type ISetMappedInterface<K, KM extends MapSetKeyType> = Readonly<{
788
792
  *
789
793
  * @returns An iterable iterator of entries.
790
794
  */
791
- entries: () => IterableIterator<readonly [K, K]>;
795
+ entries: () => IterableIterator<FixedLengthTuple<2, K>>;
792
796
 
793
797
  // Conversion
794
798
 
@@ -1444,7 +1448,7 @@ class ISetMappedClass<K, KM extends MapSetKeyType>
1444
1448
  }
1445
1449
 
1446
1450
  /** @inheritdoc */
1447
- *entries(): IterableIterator<readonly [K, K]> {
1451
+ *entries(): IterableIterator<FixedLengthTuple<2, K>> {
1448
1452
  for (const km of this.#set) {
1449
1453
  // JavaScript Set's entries() yields [value, value]
1450
1454
  const a = this.#fromKey(km);
@@ -1,5 +1,9 @@
1
1
  /* eslint-disable unicorn/prefer-iterator-to-array-at-end */
2
- import { type ReadonlyRecord, type WidenLiteral } from 'ts-type-forge';
2
+ import {
3
+ type FixedLengthTuple,
4
+ type ReadonlyRecord,
5
+ type WidenLiteral,
6
+ } from 'ts-type-forge';
3
7
  import { asUint32 } from '../number/index.mjs';
4
8
  import { unknownToString } from '../others/index.mjs';
5
9
  import { type MapSetKeyType, type SizeType } from '../types.mjs';
@@ -460,7 +464,7 @@ type ISetInterface<K extends MapSetKeyType> = Readonly<{
460
464
  *
461
465
  * @returns An iterable iterator of entries.
462
466
  */
463
- entries: () => IterableIterator<readonly [K, K]>;
467
+ entries: () => IterableIterator<FixedLengthTuple<2, K>>;
464
468
 
465
469
  // Conversion
466
470
 
@@ -913,7 +917,7 @@ class ISetClass<K extends MapSetKeyType> implements ISet<K>, Iterable<K> {
913
917
  }
914
918
 
915
919
  /** @inheritdoc */
916
- entries(): IterableIterator<readonly [K, K]> {
920
+ entries(): IterableIterator<FixedLengthTuple<2, K>> {
917
921
  return this.#set.entries();
918
922
  }
919
923
 
@@ -1,4 +1,9 @@
1
- import { type DeepReadonly, type Primitive } from 'ts-type-forge';
1
+ import {
2
+ type DeepReadonly,
3
+ type FixedLengthTuple,
4
+ type MutableFixedLengthTuple,
5
+ type Primitive,
6
+ } from 'ts-type-forge';
2
7
  import { expectType } from '../expect-type.mjs';
3
8
  import { isString } from '../guard/index.mjs';
4
9
  import { type MapSetKeyType } from '../types.mjs';
@@ -974,13 +979,11 @@ describe('ISet.entries', () => {
974
979
 
975
980
  expectType<
976
981
  typeof s0.entries,
977
- () => IterableIterator<readonly [1 | 2 | 3, 1 | 2 | 3]>
982
+ () => IterableIterator<FixedLengthTuple<2, 1 | 2 | 3>>
978
983
  >('<=');
979
984
 
980
- const result: DeepReadonly<[1 | 2 | 3, 1 | 2 | 3][]> = Array.from(
981
- s0.entries(),
982
- (x) => [x[0], x[1]],
983
- );
985
+ const result: DeepReadonly<MutableFixedLengthTuple<2, 1 | 2 | 3>[]> =
986
+ Array.from(s0.entries(), (x) => [x[0], x[1]]);
984
987
 
985
988
  assert.deepStrictEqual(
986
989
  result.toSorted((a, b) => a[0] - b[0]),
@@ -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.isFixedLengthTuple(mut_expected, 0) || Math.random() < 0.6;
589
+ Arr.isEmptyTuple(mut_expected) || Math.random() < 0.6;
590
590
 
591
591
  if (shouldEnqueue) {
592
592
  mut_counter += 1;
@@ -75,8 +75,10 @@ export type LevelOf<N> = [N] extends [SafeInt]
75
75
 
76
76
  // --- boolean fact algebra over a sign ----------------------------------------
77
77
 
78
- type And<A extends boolean, B extends boolean> = [A, B] extends [true, true]
79
- ? true
78
+ type And<A extends boolean, B extends boolean> = [A] extends [true]
79
+ ? [B] extends [true]
80
+ ? true
81
+ : false
80
82
  : false;
81
83
 
82
84
  type Or<A extends boolean, B extends boolean> = true extends A | B
@@ -170,8 +172,10 @@ type DivLevel<LA extends Level, LB extends Level> = 'number' extends LA | LB
170
172
  /** Floor division yields an integer; the safe range is preserved. */
171
173
  type DivIntLevel<LA extends Level, LB extends Level> = 'number' extends LA | LB
172
174
  ? 'number'
173
- : [LA, LB] extends ['safeint', 'safeint']
174
- ? 'safeint'
175
+ : [LA] extends ['safeint']
176
+ ? [LB] extends ['safeint']
177
+ ? 'safeint'
178
+ : 'int'
175
179
  : 'int';
176
180
 
177
181
  // --- reconstruction (sign, level) -> canonical brand -------------------------
@@ -1,11 +1,11 @@
1
- import { type NonZeroNumber } from 'ts-type-forge';
1
+ import { type FixedLengthTuple, type NonZeroNumber } from 'ts-type-forge';
2
2
  import { expectType } from '../expect-type.mjs';
3
3
  import { pipe, Result } from '../functional/index.mjs';
4
4
  import { asNonZeroFiniteNumber } from './branded-types/index.mjs';
5
5
  import { Num } from './num.mjs';
6
6
 
7
7
  const testClamp = (
8
- [a, b]: readonly [number, number],
8
+ [a, b]: FixedLengthTuple<2, number>,
9
9
  target: number,
10
10
  expected: number,
11
11
  ): void => {