ts-data-forge 1.5.2 → 2.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 (41) hide show
  1. package/README.md +56 -44
  2. package/dist/array/array-utils.d.mts +661 -166
  3. package/dist/array/array-utils.d.mts.map +1 -1
  4. package/dist/array/array-utils.mjs +719 -79
  5. package/dist/array/array-utils.mjs.map +1 -1
  6. package/dist/array/index.d.mts +0 -1
  7. package/dist/array/index.d.mts.map +1 -1
  8. package/dist/array/index.mjs +0 -1
  9. package/dist/array/index.mjs.map +1 -1
  10. package/dist/collections/queue.mjs +0 -1
  11. package/dist/collections/queue.mjs.map +1 -1
  12. package/dist/collections/stack.mjs +4 -5
  13. package/dist/collections/stack.mjs.map +1 -1
  14. package/dist/functional/pipe.d.mts +56 -61
  15. package/dist/functional/pipe.d.mts.map +1 -1
  16. package/dist/functional/pipe.mjs.map +1 -1
  17. package/dist/globals.d.mts +10 -9
  18. package/dist/index.mjs +0 -1
  19. package/dist/index.mjs.map +1 -1
  20. package/dist/json/json.mjs +0 -1
  21. package/dist/json/json.mjs.map +1 -1
  22. package/dist/number/num.d.mts +1 -1
  23. package/package.json +2 -2
  24. package/src/array/array-utils-modification.test.mts +93 -67
  25. package/src/array/array-utils-overload-type-error.test.mts +2 -2
  26. package/src/array/array-utils-reducing-value.test.mts +31 -37
  27. package/src/array/array-utils-slice-clamped.test.mts +94 -70
  28. package/src/array/array-utils-transformation.test.mts +557 -10
  29. package/src/array/array-utils.mts +1457 -516
  30. package/src/array/index.mts +0 -1
  31. package/src/collections/queue.mts +2 -2
  32. package/src/collections/stack.mts +8 -8
  33. package/src/functional/pipe.mts +65 -75
  34. package/src/globals.d.mts +10 -9
  35. package/src/number/num.mts +1 -1
  36. package/dist/array/tuple-utils.d.mts +0 -407
  37. package/dist/array/tuple-utils.d.mts.map +0 -1
  38. package/dist/array/tuple-utils.mjs +0 -345
  39. package/dist/array/tuple-utils.mjs.map +0 -1
  40. package/src/array/tuple-utils.mts +0 -498
  41. package/src/array/tuple-utils.test.mts +0 -518
@@ -15,6 +15,17 @@ import { castMutable, tp, unknownToString } from '../others/index.mjs';
15
15
  * ensuring immutability.
16
16
  */
17
17
  export namespace Arr {
18
+ type ArrayIndex<Ar extends readonly unknown[]> =
19
+ IsFixedLengthList<Ar> extends true ? IndexOfTuple<Ar> : SizeType.Arr;
20
+
21
+ type ArgArrayIndex<Ar extends readonly unknown[]> =
22
+ IsFixedLengthList<Ar> extends true ? IndexOfTuple<Ar> : SizeType.ArgArr;
23
+
24
+ type ArgArrayIndexWithNegative<Ar extends readonly unknown[]> =
25
+ IsFixedLengthList<Ar> extends true
26
+ ? IndexOfTuple<[...Ar, 0]> | NegativeIndexOfTuple<Ar>
27
+ : SizeType.ArgArrWithNegative;
28
+
18
29
  /**
19
30
  * Returns the size (length) of an array as a type-safe branded integer.
20
31
  *
@@ -40,7 +51,7 @@ export namespace Arr {
40
51
  * // Type: IntersectBrand<PositiveNumber, SizeType.Arr>
41
52
  * // Value: 3 (branded, guaranteed positive)
42
53
  *
43
- * const nonEmpty: NonEmptyArray<string> = ['a', 'b'] as NonEmptyArray<string>;
54
+ * const nonEmpty: NonEmptyArray<string> = ['a', 'b'];
44
55
  * const nonEmptySize = Arr.size(nonEmpty);
45
56
  * // Type: IntersectBrand<PositiveNumber, SizeType.Arr>
46
57
  * // Guaranteed to be > 0
@@ -70,13 +81,6 @@ export namespace Arr {
70
81
  * const indices = Arr.seq(dataSize); // Creates [0, 1, 2]
71
82
  * const zeros = Arr.zeros(dataSize); // Creates [0, 0, 0]
72
83
  *
73
- * // Safe for bounds checking
74
- * const isValidIndex = (index: number) => index >= 0 && index < dataSize;
75
- *
76
- * // Comparison with other sizes
77
- * const otherArray = ['a', 'b'];
78
- * const sizeDiff = Uint32.sub(Arr.size(data), Arr.size(otherArray)); // 1
79
- *
80
84
  * // Functional composition
81
85
  * const arrays = [
82
86
  * [1, 2],
@@ -103,17 +107,13 @@ export namespace Arr {
103
107
  * @see {@link isEmpty} for checking if size is 0
104
108
  * @see {@link isNonEmpty} for checking if size > 0
105
109
  */
106
- export function size<Ar extends NonEmptyArray<unknown>>(
110
+ export const size = <Ar extends readonly unknown[]>(
107
111
  array: Ar,
108
- ): IntersectBrand<PositiveNumber, SizeType.Arr>;
109
-
110
- export function size<Ar extends readonly unknown[]>(array: Ar): SizeType.Arr;
111
-
112
- export function size<Ar extends readonly unknown[]>(array: Ar): SizeType.Arr {
113
- return asUint32(array.length);
114
- }
115
-
116
- export const length = size;
112
+ ): Ar extends NonEmptyArray<unknown>
113
+ ? IntersectBrand<PositiveNumber, SizeType.Arr>
114
+ : SizeType.Arr =>
115
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
116
+ array.length as never;
117
117
 
118
118
  // type guard
119
119
 
@@ -179,26 +179,11 @@ export namespace Arr {
179
179
  * if (Arr.isEmpty(arr)) {
180
180
  * // arr is now typed as readonly []
181
181
  * console.log('Array is empty');
182
+ * // arr[0]; // type error!
182
183
  * return 0;
183
- * } else {
184
- * // arr is now typed as NonEmptyArray<number>
185
- * return arr[0]; // Safe access - TypeScript knows it's non-empty
186
184
  * }
187
185
  * }
188
186
  *
189
- * // Conditional processing
190
- * const data = [10, 20, 30];
191
- * if (!Arr.isEmpty(data)) {
192
- * // Safe to access elements
193
- * const firstElement = data[0]; // No undefined risk
194
- * const lastElement = data[data.length - 1];
195
- * }
196
- *
197
- * // Filtering empty arrays
198
- * const arrayList: readonly number[][] = [[1, 2], [], [3], []];
199
- * const nonEmptyArrays = arrayList.filter(arr => !Arr.isEmpty(arr));
200
- * // nonEmptyArrays: [[1, 2], [3]]
201
- *
202
187
  * // Early returns
203
188
  * function sumArray(numbers: readonly number[]): number {
204
189
  * if (Arr.isEmpty(numbers)) {
@@ -207,12 +192,6 @@ export namespace Arr {
207
192
  * return numbers.reduce((sum, n) => sum + n, 0);
208
193
  * }
209
194
  *
210
- * // Type inference examples
211
- * const testEmpty = [] as const;
212
- * const testNonEmpty = [1, 2] as const;
213
- *
214
- * expectType<Parameters<typeof Arr.isEmpty>[0], readonly unknown[]>('=');
215
- * expectType<ReturnType<typeof Arr.isEmpty>, boolean>('=');
216
195
  * ```
217
196
  *
218
197
  * @see {@link isNonEmpty} for the opposite check (non-empty arrays)
@@ -255,16 +234,14 @@ export namespace Arr {
255
234
  *
256
235
  * // Safe operations on non-empty arrays
257
236
  * function processData(data: readonly string[]) {
258
- * if (Arr.isNonEmpty(data)) {
259
- * // All of these are now safe without undefined checks
260
- * const first = data[0];
261
- * const last = data[data.length - 1];
262
- * const middle = data[Math.floor(data.length / 2)];
263
- *
264
- * // Can safely use non-empty array methods
265
- * const joined = data.join(', ');
266
- * const reduced = data.reduce((acc, item) => acc + item.length, 0);
267
- * }
237
+ * if (!Arr.isNonEmpty(data)) return; // early return pattern
238
+ *
239
+ * // This is now safe without undefined checks
240
+ * const first = data[0];
241
+ *
242
+ * // Can safely use non-empty array methods
243
+ * const lastElement = Arr.last(data);
244
+ *
268
245
  * }
269
246
  *
270
247
  * // Filtering and working with arrays
@@ -289,7 +266,7 @@ export namespace Arr {
289
266
  * }
290
267
  *
291
268
  * // numbers is now NonEmptyArray<number>
292
- * return numbers.reduce((sum, n) => sum + n, 0) / numbers.length;
269
+ * return Arr.sum(numbers) / Arr.size(numbers);
293
270
  * }
294
271
  *
295
272
  * // Functional composition
@@ -353,7 +330,7 @@ export namespace Arr {
353
330
  * Arr.isArrayOfLength([1, 2], 3); // false
354
331
  * ```
355
332
  */
356
- export const isArrayOfLength = <E, N extends SizeType.ArgArrNonNegative>(
333
+ export const isArrayOfLength = <E, N extends SizeType.ArgArr>(
357
334
  array: readonly E[],
358
335
  len: N,
359
336
  ): array is ArrayOfLength<N, E> => array.length === len;
@@ -374,7 +351,7 @@ export namespace Arr {
374
351
  * Arr.isArrayAtLeastLength([1], 2); // false
375
352
  * ```
376
353
  */
377
- export const isArrayAtLeastLength = <E, N extends SizeType.ArgArrNonNegative>(
354
+ export const isArrayAtLeastLength = <E, N extends SizeType.ArgArr>(
378
355
  array: readonly E[],
379
356
  len: N,
380
357
  ): array is ArrayAtLeastLen<N, E> => array.length >= len;
@@ -396,7 +373,7 @@ export namespace Arr {
396
373
  */
397
374
  export const indexIsInRange = <E,>(
398
375
  array: readonly E[],
399
- index: SizeType.ArgArrNonNegative,
376
+ index: SizeType.ArgArr,
400
377
  ): boolean => Num.isInRange(0, array.length)(index);
401
378
 
402
379
  // array creation
@@ -437,24 +414,15 @@ export namespace Arr {
437
414
  * expectType<typeof maybeEmpty, readonly 0[]>('=');
438
415
  * ```
439
416
  */
440
- /**
441
- * Create array of zeros with compile-time length.
442
- */
443
- export function zeros<N extends SmallUint>(len: N): ArrayOfLength<N, 0>;
444
-
445
- /**
446
- * Create non-empty array of zeros.
447
- */
448
- export function zeros(len: SizeType.ArgArrPositive): NonEmptyArray<0>;
449
-
450
- /**
451
- * Create array of zeros.
452
- */
453
- export function zeros(len: SizeType.ArgArrNonNegative): readonly 0[];
454
-
455
- export function zeros(len: SizeType.ArgArrNonNegative): readonly 0[] {
456
- return Array.from<0>({ length: len }).fill(0);
457
- }
417
+ export const zeros = <N extends SizeType.ArgArr>(
418
+ len: N,
419
+ ): N extends SmallUint
420
+ ? ArrayOfLength<N, 0>
421
+ : N extends SizeType.ArgArrPositive
422
+ ? NonEmptyArray<0>
423
+ : readonly 0[] =>
424
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
425
+ Array.from<0>({ length: len }).fill(0) as never;
458
426
 
459
427
  /**
460
428
  * Creates a sequence of consecutive integers from 0 to `len-1`.
@@ -497,19 +465,15 @@ export namespace Arr {
497
465
  * expectType<typeof single, readonly [0]>('=');
498
466
  * ```
499
467
  */
500
- export function seq<N extends SmallUint>(len: N): Seq<N>;
501
-
502
- export function seq(
503
- len: SizeType.ArgArrPositive,
504
- ): NonEmptyArray<SizeType.Arr>;
505
-
506
- export function seq(len: SizeType.ArgArrNonNegative): readonly SizeType.Arr[];
507
-
508
- export function seq(
509
- len: SizeType.ArgArrNonNegative,
510
- ): readonly SizeType.Arr[] {
511
- return Array.from({ length: len }, (_, i) => asUint32(i));
512
- }
468
+ export const seq = <N extends SizeType.ArgArr>(
469
+ len: N,
470
+ ): N extends SmallUint
471
+ ? Seq<N>
472
+ : N extends SizeType.ArgArrPositive
473
+ ? NonEmptyArray<SizeType.Arr>
474
+ : readonly SizeType.Arr[] =>
475
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
476
+ Array.from({ length: len }, (_, i) => i) as never;
513
477
 
514
478
  /**
515
479
  * Creates a new array of the specified length, with each position filled with the provided initial value.
@@ -559,29 +523,16 @@ export namespace Arr {
559
523
  * @see {@link zeros} for creating arrays filled with zeros
560
524
  * @see {@link seq} for creating sequences of consecutive integers
561
525
  */
562
- export function create<const V, N extends SmallUint>(
526
+ export const create = <const V, N extends SizeType.ArgArr>(
563
527
  len: N,
564
528
  init: V,
565
- ): ArrayOfLength<N, V>;
566
-
567
- export function create<const V>(
568
- len: SizeType.ArgArrPositive,
569
- init: V,
570
- ): NonEmptyArray<V>;
571
-
572
- export function create<const V>(
573
- len: SizeType.ArgArrNonNegative,
574
- init: V,
575
- ): readonly V[];
576
-
577
- export function create<const V>(
578
- len: SizeType.ArgArrNonNegative,
579
- init: V,
580
- ): readonly V[] {
581
- return Array.from({ length: Math.max(0, len) }, () => init);
582
- }
583
-
584
- export const newArray = create;
529
+ ): N extends SmallUint
530
+ ? ArrayOfLength<N, V>
531
+ : N extends SizeType.ArgArrPositive
532
+ ? NonEmptyArray<V>
533
+ : readonly V[] =>
534
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
535
+ Array.from({ length: Math.max(0, len) }, () => init) as never;
585
536
 
586
537
  /**
587
538
  * Creates an array from a generator function.
@@ -787,7 +738,10 @@ export namespace Arr {
787
738
  *
788
739
  * // Functional programming patterns
789
740
  * const squares = Arr.range(1, 6).map(x => x * x); // [1, 4, 9, 16, 25]
790
- * const fibonacci = Arr.range(0, 10).reduce((acc, _, i) => {\n * if (i <= 1) return [...acc, i];\n * return [...acc, acc[i-1] + acc[i-2]];\n * }, [] as number[]); // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
741
+ * const fibonacci = Arr.range(0, 10).reduce((acc, _, i) => {
742
+ * if (i <= 1) return [...acc, i];
743
+ * return [...acc, acc[i-1] + acc[i-2]];
744
+ * }, [] as number[]); // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
791
745
  *
792
746
  * // Type inference examples showing precise vs general types
793
747
  * expectType<typeof range1to4, readonly [1, 2, 3, 4]>('='); // Precise tuple
@@ -942,21 +896,21 @@ export namespace Arr {
942
896
  * @see {@link Optional.unwrapOr} for safe unwrapping with defaults
943
897
  * @see {@link Optional.map} for transforming Optional values
944
898
  */
945
- export function at<E>(
946
- array: readonly E[],
947
- index: SizeType.ArgArr,
948
- ): Optional<E>;
899
+ export function at<Ar extends readonly unknown[]>(
900
+ array: Ar,
901
+ index: ArgArrayIndexWithNegative<Ar>,
902
+ ): Optional<Ar[number]>;
949
903
 
950
904
  // Curried version
951
905
 
952
906
  export function at(
953
- index: SizeType.ArgArr,
907
+ index: SizeType.ArgArrWithNegative,
954
908
  ): <E>(array: readonly E[]) => Optional<E>;
955
909
 
956
910
  export function at<E>(
957
911
  ...args:
958
- | readonly [array: readonly E[], index: SizeType.ArgArr]
959
- | readonly [index: SizeType.ArgArr]
912
+ | readonly [array: readonly E[], index: SizeType.ArgArrWithNegative]
913
+ | readonly [index: SizeType.ArgArrWithNegative]
960
914
  ): Optional<E> | ((array: readonly E[]) => Optional<E>) {
961
915
  switch (args.length) {
962
916
  case 2: {
@@ -971,7 +925,7 @@ export namespace Arr {
971
925
  }
972
926
  case 1: {
973
927
  const [index] = args;
974
- return (array: readonly E[]) => at(array, index);
928
+ return (array) => at(array, index);
975
929
  }
976
930
  }
977
931
  }
@@ -1047,20 +1001,17 @@ export namespace Arr {
1047
1001
  * @see {@link at} for accessing elements at specific indices
1048
1002
  * @see {@link tail} for getting all elements except the first
1049
1003
  */
1050
- export function head(array: readonly []): Optional.None;
1051
-
1052
- export function head<E, L extends readonly unknown[]>(
1053
- array: readonly [E, ...L],
1054
- ): Optional.Some<E>;
1055
-
1056
- export function head<E>(array: NonEmptyArray<E>): Optional.Some<E>;
1057
-
1058
- export function head<E>(array: readonly E[]): Optional<E>;
1059
-
1060
- export function head<E>(array: readonly E[]): Optional<E> {
1061
- const element = array.at(0);
1062
- return element === undefined ? Optional.none : Optional.some(element);
1063
- }
1004
+ export const head = <Ar extends readonly unknown[]>(
1005
+ array: Ar,
1006
+ ): Ar extends readonly []
1007
+ ? Optional.None
1008
+ : Ar extends readonly [infer E, ...unknown[]]
1009
+ ? Optional.Some<E>
1010
+ : Ar extends NonEmptyArray<infer E>
1011
+ ? Optional.Some<E>
1012
+ : Optional<Ar[number]> =>
1013
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
1014
+ (array.length === 0 ? Optional.none : Optional.some(array.at(0))) as never;
1064
1015
 
1065
1016
  /**
1066
1017
  * Returns the last element of an array wrapped in an Optional.
@@ -1142,20 +1093,17 @@ export namespace Arr {
1142
1093
  * @see {@link at} for accessing elements at specific indices with negative indexing support
1143
1094
  * @see {@link butLast} for getting all elements except the last
1144
1095
  */
1145
- export function last(array: readonly []): Optional.None;
1146
-
1147
- export function last<Ar extends readonly unknown[], L>(
1148
- array: readonly [...Ar, L],
1149
- ): Optional.Some<L>;
1150
-
1151
- export function last<E>(array: NonEmptyArray<E>): Optional.Some<E>;
1152
-
1153
- export function last<E>(array: readonly E[]): Optional<E>;
1154
-
1155
- export function last<E>(array: readonly E[]): Optional<E> {
1156
- const element = array.at(-1);
1157
- return element === undefined ? Optional.none : Optional.some(element);
1158
- }
1096
+ export const last = <Ar extends readonly unknown[]>(
1097
+ array: Ar,
1098
+ ): Ar extends readonly []
1099
+ ? Optional.None
1100
+ : Ar extends readonly [...unknown[], infer E]
1101
+ ? Optional.Some<E>
1102
+ : Ar extends NonEmptyArray<infer E>
1103
+ ? Optional.Some<E>
1104
+ : Optional<Ar[number]> =>
1105
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
1106
+ (array.length === 0 ? Optional.none : Optional.some(array.at(-1))) as never;
1159
1107
 
1160
1108
  // slicing
1161
1109
 
@@ -1242,21 +1190,25 @@ export namespace Arr {
1242
1190
  * @see {@link skip} for skipping the first N elements
1243
1191
  * @see {@link takeLast} for taking the last N elements
1244
1192
  */
1245
- export function sliceClamped<E>(
1246
- array: readonly E[],
1247
- start: SizeType.ArgArr,
1248
- end: SizeType.ArgArr,
1249
- ): readonly E[];
1193
+ export function sliceClamped<Ar extends readonly unknown[]>(
1194
+ array: Ar,
1195
+ start: ArgArrayIndexWithNegative<Ar>,
1196
+ end: ArgArrayIndexWithNegative<Ar>,
1197
+ ): readonly Ar[number][];
1250
1198
 
1251
1199
  export function sliceClamped(
1252
- start: SizeType.ArgArr,
1253
- end: SizeType.ArgArr,
1200
+ start: SizeType.ArgArrWithNegative,
1201
+ end: SizeType.ArgArrWithNegative,
1254
1202
  ): <E>(array: readonly E[]) => readonly E[];
1255
1203
 
1256
1204
  export function sliceClamped<E>(
1257
1205
  ...args:
1258
- | readonly [readonly E[], SizeType.ArgArr, SizeType.ArgArr]
1259
- | readonly [SizeType.ArgArr, SizeType.ArgArr]
1206
+ | readonly [
1207
+ readonly E[],
1208
+ SizeType.ArgArrWithNegative,
1209
+ SizeType.ArgArrWithNegative,
1210
+ ]
1211
+ | readonly [SizeType.ArgArrWithNegative, SizeType.ArgArrWithNegative]
1260
1212
  ): readonly E[] | ((array: readonly E[]) => readonly E[]) {
1261
1213
  switch (args.length) {
1262
1214
  case 3: {
@@ -1332,41 +1284,37 @@ export namespace Arr {
1332
1284
  * console.log(result); // [1, 2, 3]
1333
1285
  * ```
1334
1286
  */
1335
- export function take<Ar extends readonly unknown[], N extends SmallUint>(
1287
+ export function take<
1288
+ Ar extends readonly unknown[],
1289
+ N extends SizeType.ArgArr,
1290
+ >(
1336
1291
  array: Ar,
1337
1292
  num: N,
1338
- ): List.Take<N, Ar>;
1339
-
1340
- export function take<N extends SmallUint>(
1293
+ ): N extends SmallUint
1294
+ ? List.Take<N, Ar>
1295
+ : N extends SizeType.ArgArrPositive
1296
+ ? Ar extends NonEmptyArray<unknown>
1297
+ ? NonEmptyArray<Ar[number]>
1298
+ : readonly Ar[number][]
1299
+ : readonly Ar[number][];
1300
+
1301
+ export function take<N extends SizeType.ArgArr>(
1341
1302
  num: N,
1342
- ): <Ar extends readonly unknown[]>(array: Ar) => List.Take<N, Ar>;
1343
-
1344
- export function take<E>(
1345
- array: NonEmptyArray<E>,
1346
- num: SizeType.ArgArrPositive,
1347
- ): NonEmptyArray<E>;
1348
-
1349
- export function take(
1350
- num: SizeType.ArgArrPositive,
1351
- ): <E>(array: NonEmptyArray<E>) => NonEmptyArray<E>;
1352
-
1353
- export function take<E>(
1354
- array: readonly E[],
1355
- num: SizeType.ArgArrNonNegative,
1356
- ): readonly E[];
1357
-
1358
- export function take(
1359
- num: SizeType.ArgArrNonNegative,
1360
- ): <E>(array: readonly E[]) => readonly E[];
1303
+ ): <Ar extends readonly unknown[]>(
1304
+ array: Ar,
1305
+ ) => N extends SmallUint
1306
+ ? List.Take<N, Ar>
1307
+ : N extends SizeType.ArgArrPositive
1308
+ ? Ar extends NonEmptyArray<unknown>
1309
+ ? NonEmptyArray<Ar[number]>
1310
+ : readonly Ar[number][]
1311
+ : readonly Ar[number][];
1361
1312
 
1362
1313
  export function take<E>(
1363
1314
  ...args:
1364
- | readonly [array: readonly E[], num: SizeType.ArgArrNonNegative]
1365
- | readonly [num: SizeType.ArgArrNonNegative]
1366
- ):
1367
- | readonly E[]
1368
- | ((array: NonEmptyArray<E>) => NonEmptyArray<E>)
1369
- | ((array: readonly E[]) => readonly E[]) {
1315
+ | readonly [array: readonly E[], num: SizeType.ArgArr]
1316
+ | readonly [num: SizeType.ArgArr]
1317
+ ): readonly E[] | ((array: readonly E[]) => readonly E[]) {
1370
1318
  switch (args.length) {
1371
1319
  case 2: {
1372
1320
  const [array, num] = args;
@@ -1374,7 +1322,7 @@ export namespace Arr {
1374
1322
  }
1375
1323
  case 1: {
1376
1324
  const [num] = args;
1377
- return (array: readonly E[]) => take(array, num);
1325
+ return (array) => take(array, num);
1378
1326
  }
1379
1327
  }
1380
1328
  }
@@ -1402,41 +1350,37 @@ export namespace Arr {
1402
1350
  * console.log(result); // [4, 5]
1403
1351
  * ```
1404
1352
  */
1405
- export function takeLast<Ar extends readonly unknown[], N extends SmallUint>(
1353
+ export function takeLast<
1354
+ Ar extends readonly unknown[],
1355
+ N extends SizeType.ArgArr,
1356
+ >(
1406
1357
  array: Ar,
1407
1358
  num: N,
1408
- ): List.TakeLast<N, Ar>;
1409
-
1410
- export function takeLast<N extends SmallUint>(
1359
+ ): N extends SmallUint
1360
+ ? List.TakeLast<N, Ar>
1361
+ : N extends SizeType.ArgArrPositive
1362
+ ? Ar extends NonEmptyArray<unknown>
1363
+ ? NonEmptyArray<Ar[number]>
1364
+ : readonly Ar[number][]
1365
+ : readonly Ar[number][];
1366
+
1367
+ export function takeLast<N extends SizeType.ArgArr>(
1411
1368
  num: N,
1412
- ): <Ar extends readonly unknown[]>(array: Ar) => List.TakeLast<N, Ar>;
1413
-
1414
- export function takeLast<E>(
1415
- array: NonEmptyArray<E>,
1416
- num: SizeType.ArgArrPositive,
1417
- ): NonEmptyArray<E>;
1418
-
1419
- export function takeLast(
1420
- num: SizeType.ArgArrPositive,
1421
- ): <E>(array: NonEmptyArray<E>) => NonEmptyArray<E>;
1422
-
1423
- export function takeLast<E>(
1424
- array: readonly E[],
1425
- num: SizeType.ArgArrNonNegative,
1426
- ): readonly E[];
1427
-
1428
- export function takeLast(
1429
- num: SizeType.ArgArrNonNegative,
1430
- ): <E>(array: readonly E[]) => readonly E[];
1369
+ ): <Ar extends readonly unknown[]>(
1370
+ array: Ar,
1371
+ ) => N extends SmallUint
1372
+ ? List.TakeLast<N, Ar>
1373
+ : N extends SizeType.ArgArrPositive
1374
+ ? Ar extends NonEmptyArray<unknown>
1375
+ ? NonEmptyArray<Ar[number]>
1376
+ : readonly Ar[number][]
1377
+ : readonly Ar[number][];
1431
1378
 
1432
1379
  export function takeLast<E>(
1433
1380
  ...args:
1434
- | readonly [array: readonly E[], num: SizeType.ArgArrNonNegative]
1435
- | readonly [num: SizeType.ArgArrNonNegative]
1436
- ):
1437
- | readonly E[]
1438
- | ((array: NonEmptyArray<E>) => NonEmptyArray<E>)
1439
- | ((array: readonly E[]) => readonly E[]) {
1381
+ | readonly [array: readonly E[], num: SizeType.ArgArr]
1382
+ | readonly [num: SizeType.ArgArr]
1383
+ ): readonly E[] | ((array: readonly E[]) => readonly E[]) {
1440
1384
  switch (args.length) {
1441
1385
  case 2: {
1442
1386
  const [array, num] = args;
@@ -1444,7 +1388,7 @@ export namespace Arr {
1444
1388
  }
1445
1389
  case 1: {
1446
1390
  const [num] = args;
1447
- return (array: readonly E[]) => takeLast(array, num);
1391
+ return (array) => takeLast(array, num);
1448
1392
  }
1449
1393
  }
1450
1394
  }
@@ -1472,41 +1416,26 @@ export namespace Arr {
1472
1416
  * console.log(result); // [3, 4, 5]
1473
1417
  * ```
1474
1418
  */
1475
- export function skip<Ar extends readonly unknown[], N extends SmallUint>(
1419
+ export function skip<
1420
+ Ar extends readonly unknown[],
1421
+ N extends SizeType.ArgArr,
1422
+ >(
1476
1423
  array: Ar,
1477
1424
  num: N,
1478
- ): List.Skip<N, Ar>;
1479
-
1480
- export function skip<E>(
1481
- array: NonEmptyArray<E>,
1482
- num: SizeType.ArgArrPositive,
1483
- ): readonly E[];
1425
+ ): N extends SmallUint ? List.Skip<N, Ar> : readonly Ar[number][];
1484
1426
 
1485
- export function skip<E>(
1486
- array: readonly E[],
1487
- num: SizeType.ArgArrNonNegative,
1488
- ): readonly E[];
1489
-
1490
- export function skip<N extends SmallUint>(
1427
+ // curried version
1428
+ export function skip<N extends SizeType.ArgArr>(
1491
1429
  num: N,
1492
- ): <Ar extends readonly unknown[]>(array: Ar) => List.Skip<N, Ar>;
1493
-
1494
- export function skip(
1495
- num: SizeType.ArgArrPositive,
1496
- ): <E>(array: NonEmptyArray<E>) => readonly E[];
1497
-
1498
- export function skip(
1499
- num: SizeType.ArgArrNonNegative,
1500
- ): <E>(array: readonly E[]) => readonly E[];
1430
+ ): <Ar extends readonly unknown[]>(
1431
+ array: Ar,
1432
+ ) => N extends SmallUint ? List.Skip<N, Ar> : readonly Ar[number][];
1501
1433
 
1502
1434
  export function skip<E>(
1503
1435
  ...args:
1504
- | readonly [readonly E[], SizeType.ArgArrNonNegative]
1505
- | readonly [SizeType.ArgArrNonNegative]
1506
- ):
1507
- | readonly E[]
1508
- | ((array: NonEmptyArray<E>) => readonly E[])
1509
- | ((array: readonly E[]) => readonly E[]) {
1436
+ | readonly [readonly E[], SizeType.ArgArr]
1437
+ | readonly [SizeType.ArgArr]
1438
+ ): readonly E[] | ((array: readonly E[]) => readonly E[]) {
1510
1439
  switch (args.length) {
1511
1440
  case 2: {
1512
1441
  const [array, num] = args;
@@ -1514,7 +1443,7 @@ export namespace Arr {
1514
1443
  }
1515
1444
  case 1: {
1516
1445
  const [num] = args;
1517
- return (array: readonly E[]) => skip(array, num);
1446
+ return (array) => skip(array, num);
1518
1447
  }
1519
1448
  }
1520
1449
  }
@@ -1542,28 +1471,25 @@ export namespace Arr {
1542
1471
  * console.log(result); // [1, 2, 3]
1543
1472
  * ```
1544
1473
  */
1545
- export function skipLast<Ar extends readonly unknown[], N extends SmallUint>(
1474
+ export function skipLast<
1475
+ Ar extends readonly unknown[],
1476
+ N extends SizeType.ArgArr,
1477
+ >(
1546
1478
  array: Ar,
1547
1479
  num: N,
1548
- ): List.SkipLast<N, Ar>;
1480
+ ): N extends SmallUint ? List.SkipLast<N, Ar> : readonly Ar[number][];
1549
1481
 
1550
- export function skipLast<N extends SmallUint>(
1482
+ // curried version
1483
+ export function skipLast<N extends SizeType.ArgArr>(
1551
1484
  num: N,
1552
- ): <Ar extends readonly unknown[]>(array: Ar) => List.SkipLast<N, Ar>;
1553
-
1554
- export function skipLast<E>(
1555
- array: readonly E[],
1556
- num: SizeType.ArgArrNonNegative,
1557
- ): readonly E[];
1558
-
1559
- export function skipLast(
1560
- num: SizeType.ArgArrNonNegative,
1561
- ): <E>(array: readonly E[]) => readonly E[];
1485
+ ): <Ar extends readonly unknown[]>(
1486
+ array: Ar,
1487
+ ) => N extends SmallUint ? List.SkipLast<N, Ar> : readonly Ar[number][];
1562
1488
 
1563
1489
  export function skipLast<E>(
1564
1490
  ...args:
1565
- | readonly [array: readonly E[], num: SizeType.ArgArrNonNegative]
1566
- | readonly [num: SizeType.ArgArrNonNegative]
1491
+ | readonly [array: readonly E[], num: SizeType.ArgArr]
1492
+ | readonly [num: SizeType.ArgArr]
1567
1493
  ): readonly E[] | ((array: readonly E[]) => readonly E[]) {
1568
1494
  switch (args.length) {
1569
1495
  case 2: {
@@ -1572,13 +1498,91 @@ export namespace Arr {
1572
1498
  }
1573
1499
  case 1: {
1574
1500
  const [num] = args;
1575
- return (array: readonly E[]) => skipLast(array, num);
1501
+ return (array) => skipLast(array, num);
1576
1502
  }
1577
1503
  }
1578
1504
  }
1579
1505
 
1580
1506
  // modification (returns new array)
1581
1507
 
1508
+ /**
1509
+ * Returns a new tuple with the element at the specified index replaced.
1510
+ *
1511
+ * This operation is type-safe with compile-time index validation.
1512
+ * The resulting tuple type reflects that the element at the given index
1513
+ * may be either the new type or the original type.
1514
+ *
1515
+ * @template T - The type of the input tuple
1516
+ * @template N - The type of the new value to set
1517
+ * @param tpl - The input tuple
1518
+ * @param index - The index to update (must be valid for the tuple length)
1519
+ * @param newValue - The new value to place at the index
1520
+ * @returns A new tuple with the updated element
1521
+ *
1522
+ * @example
1523
+ * ```typescript
1524
+ * // Basic usage
1525
+ * const tpl = ['a', 'b', 'c'] as const;
1526
+ * const updated = Arr.set(tpl, 1, 'B'); // readonly ['a', 'B', 'c']
1527
+ *
1528
+ * // Type changes are reflected
1529
+ * const mixed = [1, 'hello', true] as const;
1530
+ * const withNumber = Arr.set(mixed, 1, 42);
1531
+ * // readonly [1, 42 | 'hello', true]
1532
+ *
1533
+ * // Compile-time index validation
1534
+ * const short = [1, 2] as const;
1535
+ * // Arr.set(short, 2, 3); // Error: index 2 is out of bounds
1536
+ *
1537
+ * // Different value types
1538
+ * const nums = [1, 2, 3] as const;
1539
+ * const withString = Arr.set(nums, 0, 'first');
1540
+ * // readonly ['first' | 1, 2, 3]
1541
+ * ```
1542
+ */
1543
+ export function set<
1544
+ const Ar extends readonly unknown[],
1545
+ const V = Ar[number],
1546
+ >(
1547
+ array: Ar,
1548
+ index: ArgArrayIndex<Ar>,
1549
+ newValue: V,
1550
+ ): IsFixedLengthList<Ar> extends true
1551
+ ? Readonly<{ [K in keyof Ar]: Ar[K] | V }>
1552
+ : Ar extends NonEmptyArray<unknown>
1553
+ ? NonEmptyArray<Ar[number] | V>
1554
+ : readonly (Ar[number] | V)[];
1555
+
1556
+ // curried version
1557
+ export function set<const V>(
1558
+ index: SizeType.ArgArr,
1559
+ newValue: V,
1560
+ ): <const Ar extends readonly unknown[]>(
1561
+ array: Ar,
1562
+ ) => IsFixedLengthList<Ar> extends true
1563
+ ? Readonly<{ [K in keyof Ar]: Ar[K] | V }>
1564
+ : Ar extends NonEmptyArray<unknown>
1565
+ ? NonEmptyArray<Ar[number] | V>
1566
+ : readonly (Ar[number] | V)[];
1567
+
1568
+ export function set<E, const V = E>(
1569
+ ...args:
1570
+ | readonly [array: readonly E[], index: SizeType.ArgArr, newValue: V]
1571
+ | readonly [index: SizeType.ArgArr, newValue: V]
1572
+ ): readonly (E | V)[] | ((array: readonly E[]) => readonly (E | V)[]) {
1573
+ switch (args.length) {
1574
+ case 3: {
1575
+ const [array, index, newValue] = args;
1576
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
1577
+ return (array as (E | V)[]).with(index, newValue);
1578
+ }
1579
+ case 2: {
1580
+ const [index, newValue] = args;
1581
+ return (array) => set(array, index, newValue);
1582
+ }
1583
+ }
1584
+ }
1585
+
1582
1586
  /**
1583
1587
  * Returns a new array with the element at the specified index updated by a function.
1584
1588
  *
@@ -1600,9 +1604,9 @@ export namespace Arr {
1600
1604
  * updater, returns a reusable function that can be applied to arrays.
1601
1605
  *
1602
1606
  * @template E The type of elements in the original array.
1603
- * @template U The type of the value returned by the updater function.
1607
+ * @template V The type of the value returned by the updater function.
1604
1608
  * @param array The input array to update. Can be any readonly array.
1605
- * @param index The index of the element to update. Must be a non-negative {@link SizeType.ArgArrNonNegative}.
1609
+ * @param index The index of the element to update. Must be a non-negative {@link SizeType.ArgArr}.
1606
1610
  * - **Valid range:** `0 <= index < array.length`
1607
1611
  * - **Out of bounds:** Returns original array unchanged
1608
1612
  * - **Negative values:** Not allowed by type system (non-negative constraint)
@@ -1730,40 +1734,52 @@ export namespace Arr {
1730
1734
  * ```
1731
1735
  *
1732
1736
  * @see {@link Array.prototype.with} for the native method with different error handling
1733
- * @see {@link SizeType.ArgArrNonNegative} for the index type constraint
1737
+ * @see {@link SizeType.ArgArr} for the index type constraint
1734
1738
  * @see Immutable update patterns for functional programming approaches
1735
1739
  */
1736
- export function toUpdated<E, U>(
1737
- array: readonly E[],
1738
- index: SizeType.ArgArrNonNegative,
1739
- updater: (prev: E) => U,
1740
- ): readonly (E | U)[];
1741
-
1742
- export function toUpdated<E, U>(
1743
- index: SizeType.ArgArrNonNegative,
1744
- updater: (prev: E) => U,
1745
- ): (array: readonly E[]) => readonly (E | U)[];
1740
+ export function toUpdated<
1741
+ const Ar extends readonly unknown[],
1742
+ const V = Ar[number],
1743
+ >(
1744
+ array: Ar,
1745
+ index: ArgArrayIndex<Ar>,
1746
+ updater: (prev: Ar[number]) => V,
1747
+ ): IsFixedLengthList<Ar> extends true
1748
+ ? Readonly<{ [K in keyof Ar]: Ar[K] | V }>
1749
+ : Ar extends NonEmptyArray<unknown>
1750
+ ? NonEmptyArray<Ar[number] | V>
1751
+ : readonly (Ar[number] | V)[];
1752
+
1753
+ // curried version
1754
+ export function toUpdated<E, const V = E>(
1755
+ index: SizeType.ArgArr,
1756
+ updater: (prev: E) => V,
1757
+ ): <const Ar extends readonly E[]>(
1758
+ array: Ar,
1759
+ ) => IsFixedLengthList<Ar> extends true
1760
+ ? Readonly<{ [K in keyof Ar]: Ar[K] | V }>
1761
+ : Ar extends NonEmptyArray<unknown>
1762
+ ? NonEmptyArray<Ar[number] | V>
1763
+ : readonly (Ar[number] | V)[];
1746
1764
 
1747
- export function toUpdated<E, U>(
1765
+ export function toUpdated<E, V = E>(
1748
1766
  ...args:
1749
1767
  | readonly [
1750
1768
  array: readonly E[],
1751
- index: SizeType.ArgArrNonNegative,
1752
- updater: (prev: E) => U,
1769
+ index: SizeType.ArgArr,
1770
+ updater: (prev: E) => V,
1753
1771
  ]
1754
- | readonly [index: SizeType.ArgArrNonNegative, updater: (prev: E) => U]
1755
- ): readonly (E | U)[] | ((array: readonly E[]) => readonly (E | U)[]) {
1772
+ | readonly [index: SizeType.ArgArr, updater: (prev: E) => V]
1773
+ ): readonly (E | V)[] | ((array: readonly E[]) => readonly (E | V)[]) {
1756
1774
  switch (args.length) {
1757
1775
  case 3: {
1758
1776
  const [array, index, updater] = args;
1759
- return index < 0 || index >= array.length
1760
- ? array // Return a copy if index is out of bounds
1761
- : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-unsafe-type-assertion
1762
- (array as (E | U)[]).with(index, updater(array[index]!));
1777
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-unsafe-type-assertion
1778
+ return (array as (E | V)[]).with(index, updater(array[index]!));
1763
1779
  }
1764
1780
  case 2: {
1765
1781
  const [index, updater] = args;
1766
- return (array: readonly E[]) => toUpdated(array, index, updater);
1782
+ return (array) => toUpdated(array, index, updater);
1767
1783
  }
1768
1784
  }
1769
1785
  }
@@ -1787,25 +1803,35 @@ export namespace Arr {
1787
1803
  * console.log(result); // [99, 1, 2, 3]
1788
1804
  * ```
1789
1805
  */
1790
- export function toInserted<E, const V = E>(
1791
- array: readonly E[],
1792
- index: SizeType.ArgArrNonNegative,
1806
+ export function toInserted<
1807
+ Ar extends readonly unknown[],
1808
+ const V = Ar[number],
1809
+ >(
1810
+ array: Ar,
1811
+ index: ArgArrayIndexWithNegative<Ar>,
1793
1812
  newValue: V,
1794
- ): NonEmptyArray<E | V>;
1813
+ ): IsFixedLengthList<Ar> extends true
1814
+ ? ArrayOfLength<CastToNumber<Increment<Ar['length']>>, Ar[number] | V>
1815
+ : NonEmptyArray<Ar[number] | V>;
1795
1816
 
1796
- export function toInserted<E, const V = E>(
1797
- index: SizeType.ArgArrNonNegative,
1817
+ // curried version
1818
+ export function toInserted<const V>(
1819
+ index: SizeType.ArgArrWithNegative,
1798
1820
  newValue: V,
1799
- ): (array: readonly E[]) => NonEmptyArray<E | V>;
1821
+ ): <Ar extends readonly unknown[]>(
1822
+ array: Ar,
1823
+ ) => IsFixedLengthList<Ar> extends true
1824
+ ? ArrayOfLength<CastToNumber<Increment<Ar['length']>>, Ar[number] | V>
1825
+ : NonEmptyArray<Ar[number] | V>;
1800
1826
 
1801
1827
  export function toInserted<E, const V = E>(
1802
1828
  ...args:
1803
1829
  | readonly [
1804
1830
  array: readonly E[],
1805
- index: SizeType.ArgArrNonNegative,
1831
+ index: SizeType.ArgArrWithNegative,
1806
1832
  newValue: V,
1807
1833
  ]
1808
- | readonly [index: SizeType.ArgArrNonNegative, newValue: V]
1834
+ | readonly [index: SizeType.ArgArrWithNegative, newValue: V]
1809
1835
  ): NonEmptyArray<E | V> | ((array: readonly E[]) => NonEmptyArray<E | V>) {
1810
1836
  switch (args.length) {
1811
1837
  case 3: {
@@ -1819,11 +1845,13 @@ export namespace Arr {
1819
1845
  }
1820
1846
  case 2: {
1821
1847
  const [index, newValue] = args;
1822
- return (array: readonly E[]) => toInserted(array, index, newValue);
1848
+ return (array) => toInserted(array, index, newValue);
1823
1849
  }
1824
1850
  }
1825
1851
  }
1826
1852
 
1853
+ type CastToNumber<T> = T extends number ? T : never;
1854
+
1827
1855
  /**
1828
1856
  * Returns a new array with the element at the specified index removed.
1829
1857
  * If index is out of bounds, `toSpliced` handles this (usually by returning a copy).
@@ -1842,19 +1870,19 @@ export namespace Arr {
1842
1870
  * console.log(result); // [20, 30]
1843
1871
  * ```
1844
1872
  */
1845
- export function toRemoved<E>(
1846
- array: readonly E[],
1847
- index: SizeType.ArgArrNonNegative,
1848
- ): readonly E[];
1873
+ export function toRemoved<Ar extends readonly unknown[]>(
1874
+ array: Ar,
1875
+ index: ArgArrayIndexWithNegative<Ar>,
1876
+ ): readonly Ar[number][];
1849
1877
 
1850
1878
  export function toRemoved(
1851
- index: SizeType.ArgArrNonNegative,
1879
+ index: SizeType.ArgArrWithNegative,
1852
1880
  ): <E>(array: readonly E[]) => readonly E[];
1853
1881
 
1854
1882
  export function toRemoved<E>(
1855
1883
  ...args:
1856
- | readonly [array: readonly E[], index: SizeType.ArgArrNonNegative]
1857
- | readonly [index: SizeType.ArgArrNonNegative]
1884
+ | readonly [array: readonly E[], index: SizeType.ArgArrWithNegative]
1885
+ | readonly [index: SizeType.ArgArrWithNegative]
1858
1886
  ): readonly E[] | ((array: readonly E[]) => readonly E[]) {
1859
1887
  switch (args.length) {
1860
1888
  case 2: {
@@ -1863,7 +1891,7 @@ export namespace Arr {
1863
1891
  }
1864
1892
  case 1: {
1865
1893
  const [index] = args;
1866
- return (array: readonly E[]) => toRemoved(array, index);
1894
+ return (array) => toRemoved(array, index);
1867
1895
  }
1868
1896
  }
1869
1897
  }
@@ -1962,28 +1990,54 @@ export namespace Arr {
1962
1990
  }
1963
1991
 
1964
1992
  /**
1965
- * Fills an array with a value (creates a new filled array).
1966
- * @param array The array.
1967
- * @param value The value to fill with.
1968
- * @param start The start index.
1969
- * @param end The end index.
1970
- * @returns A new filled array.
1993
+ * Creates a new array of the same length filled with a specified value.
1994
+ *
1995
+ * This function replaces all elements in the array with the provided value,
1996
+ * maintaining the original array's length and structure. It provides type-safe
1997
+ * array filling with precise return types.
1998
+ *
1999
+ * @template Ar The exact type of the input array.
2000
+ * @template V The type of the fill value.
2001
+ * @param array The array to fill.
2002
+ * @param value The value to fill the array with.
2003
+ * @returns A new array of the same length filled with the specified value:
2004
+ * - For fixed-length arrays: returns `ArrayOfLength<Ar['length'], V>`
2005
+ * - For non-empty arrays: returns `NonEmptyArray<V>`
2006
+ * - For general arrays: returns `readonly V[]`
2007
+ *
1971
2008
  * @example
1972
2009
  * ```typescript
1973
2010
  * // Regular usage
1974
- * const arr = [1, 2, 3, 4, 5];
1975
- * const result = Arr.toFilled(arr, 0, 1, 4);
1976
- * console.log(result); // [1, 0, 0, 0, 5]
2011
+ * const numbers = [1, 2, 3, 4, 5];
2012
+ * const zeros = Arr.toFilled(numbers, 0); // [0, 0, 0, 0, 0]
1977
2013
  *
1978
2014
  * // Curried usage for pipe composition
1979
- * const fillWithZeros = Arr.toFilled(0, 1, 3);
1980
- * const result2 = pipe([1, 2, 3, 4]).map(fillWithZeros).value;
1981
- * console.log(result2); // [1, 0, 0, 4]
2015
+ * const fillWithX = Arr.toFilled('X');
2016
+ * const result = pipe(['a', 'b', 'c']).map(fillWithX).value; // ['X', 'X', 'X']
1982
2017
  * ```
2018
+ *
2019
+ * @see {@link toRangeFilled} for filling only a specific range
2020
+ * @see {@link create} for creating new arrays filled with a value
1983
2021
  */
1984
- export function toFilled<E>(array: readonly E[], value: E): readonly E[];
1985
-
1986
- export function toFilled<E>(value: E): (array: readonly E[]) => readonly E[];
2022
+ export function toFilled<Ar extends readonly unknown[], const V>(
2023
+ array: Ar,
2024
+ value: V,
2025
+ ): IsFixedLengthList<Ar> extends true
2026
+ ? ArrayOfLength<Ar['length'], V>
2027
+ : Ar extends NonEmptyArray<unknown>
2028
+ ? NonEmptyArray<V>
2029
+ : readonly V[];
2030
+
2031
+ // curried version
2032
+ export function toFilled<const V>(
2033
+ value: V,
2034
+ ): <Ar extends readonly unknown[]>(
2035
+ array: Ar,
2036
+ ) => IsFixedLengthList<Ar> extends true
2037
+ ? ArrayOfLength<Ar['length'], V>
2038
+ : Ar extends NonEmptyArray<unknown>
2039
+ ? NonEmptyArray<V>
2040
+ : readonly V[];
1987
2041
 
1988
2042
  export function toFilled<E>(
1989
2043
  ...args: readonly [array: readonly E[], value: E] | readonly [value: E]
@@ -1991,9 +2045,7 @@ export namespace Arr {
1991
2045
  switch (args.length) {
1992
2046
  case 2: {
1993
2047
  const [array, value] = args;
1994
- const cp = castMutable(copy(array));
1995
- cp.fill(value);
1996
- return cp;
2048
+ return create(asPositiveUint32(array.length), value);
1997
2049
  }
1998
2050
  case 1: {
1999
2051
  const [value] = args;
@@ -2002,33 +2054,86 @@ export namespace Arr {
2002
2054
  }
2003
2055
  }
2004
2056
 
2005
- export function toRangeFilled<E>(
2006
- array: readonly E[],
2007
- value: E,
2008
- fillRange: readonly [start: SizeType.ArgArr, end: SizeType.ArgArr],
2009
- ): readonly E[];
2010
-
2011
- export function toRangeFilled<E>(
2012
- value: E,
2013
- fillRange: readonly [start: SizeType.ArgArr, end: SizeType.ArgArr],
2014
- ): (array: readonly E[]) => readonly E[];
2057
+ /**
2058
+ * Creates a new array with a specific range filled with a specified value.
2059
+ *
2060
+ * This function fills only the specified range of indices with the provided value,
2061
+ * leaving other elements unchanged. It provides type-safe range filling with
2062
+ * precise return types.
2063
+ *
2064
+ * @template Ar The exact type of the input array.
2065
+ * @template V The type of the fill value.
2066
+ * @param array The array to fill a range of.
2067
+ * @param value The value to fill the range with.
2068
+ * @param fillRange A tuple containing [start, end] indices for the range to fill.
2069
+ * @returns A new array with the specified range filled:
2070
+ * - For fixed-length arrays: returns `ArrayOfLength<Ar['length'], V | Ar[number]>`
2071
+ * - For non-empty arrays: returns `NonEmptyArray<V | Ar[number]>`
2072
+ * - For general arrays: returns `readonly (V | Ar[number])[]`
2073
+ *
2074
+ * @example
2075
+ * ```typescript
2076
+ * // Regular usage
2077
+ * const numbers = [1, 2, 3, 4, 5];
2078
+ * const result = Arr.toRangeFilled(numbers, 0, [1, 4]); // [1, 0, 0, 0, 5]
2079
+ *
2080
+ * // Curried usage for pipe composition
2081
+ * const fillMiddleWithX = Arr.toRangeFilled('X', [1, 3]);
2082
+ * const result2 = pipe(['a', 'b', 'c', 'd']).map(fillMiddleWithX).value; // ['a', 'X', 'X', 'd']
2083
+ * ```
2084
+ *
2085
+ * @see {@link toFilled} for filling the entire array
2086
+ */
2087
+ export function toRangeFilled<Ar extends readonly unknown[], const V>(
2088
+ array: Ar,
2089
+ value: V,
2090
+ fillRange: readonly [
2091
+ start: ArgArrayIndexWithNegative<Ar>,
2092
+ end: ArgArrayIndexWithNegative<Ar>,
2093
+ ],
2094
+ ): IsFixedLengthList<Ar> extends true
2095
+ ? ArrayOfLength<Ar['length'], V | Ar[number]>
2096
+ : Ar extends NonEmptyArray<unknown>
2097
+ ? NonEmptyArray<V | Ar[number]>
2098
+ : readonly (V | Ar[number])[];
2099
+
2100
+ // curried version
2101
+ export function toRangeFilled<const V>(
2102
+ value: V,
2103
+ fillRange: readonly [
2104
+ start: SizeType.ArgArrWithNegative,
2105
+ end: SizeType.ArgArrWithNegative,
2106
+ ],
2107
+ ): <Ar extends readonly unknown[]>(
2108
+ array: Ar,
2109
+ ) => IsFixedLengthList<Ar> extends true
2110
+ ? ArrayOfLength<Ar['length'], V | Ar[number]>
2111
+ : Ar extends NonEmptyArray<unknown>
2112
+ ? NonEmptyArray<V | Ar[number]>
2113
+ : readonly (V | Ar[number])[];
2015
2114
 
2016
- export function toRangeFilled<E>(
2115
+ export function toRangeFilled<E, const V>(
2017
2116
  ...args:
2018
2117
  | readonly [
2019
2118
  array: readonly E[],
2020
- value: E,
2021
- fillRange: readonly [start: SizeType.ArgArr, end: SizeType.ArgArr],
2119
+ value: V,
2120
+ fillRange: readonly [
2121
+ start: SizeType.ArgArrWithNegative,
2122
+ end: SizeType.ArgArrWithNegative,
2123
+ ],
2022
2124
  ]
2023
2125
  | readonly [
2024
- value: E,
2025
- fillRange: readonly [start: SizeType.ArgArr, end: SizeType.ArgArr],
2126
+ value: V,
2127
+ fillRange: readonly [
2128
+ start: SizeType.ArgArrWithNegative,
2129
+ end: SizeType.ArgArrWithNegative,
2130
+ ],
2026
2131
  ]
2027
- ): readonly E[] | ((array: readonly E[]) => readonly E[]) {
2132
+ ): readonly (E | V)[] | ((array: readonly E[]) => readonly (E | V)[]) {
2028
2133
  switch (args.length) {
2029
2134
  case 3: {
2030
2135
  const [array, value, [start, end]] = args;
2031
- const cp = castMutable(copy(array));
2136
+ const cp: (E | V)[] = castMutable(copy(array));
2032
2137
  cp.fill(value, start, end);
2033
2138
  return cp;
2034
2139
  }
@@ -2078,10 +2183,15 @@ export namespace Arr {
2078
2183
  * @see {@link indexOf} for finding elements by equality
2079
2184
  * @see {@link Optional} for working with the returned Optional values
2080
2185
  */
2081
- export function find<E>(
2186
+ export function find<E, F extends E>(
2082
2187
  array: readonly E[],
2083
- predicate: (value: E, index: SizeType.Arr, arr: readonly E[]) => boolean,
2084
- ): Optional<E>;
2188
+ predicate: (value: E, index: SizeType.Arr, arr: readonly E[]) => value is F,
2189
+ ): Optional<F>;
2190
+
2191
+ export function find<Ar extends readonly unknown[]>(
2192
+ array: Ar,
2193
+ predicate: (value: Ar[number], index: ArrayIndex<Ar>, arr: Ar) => boolean,
2194
+ ): Optional<Ar[number]>;
2085
2195
 
2086
2196
  export function find<E>(
2087
2197
  predicate: (value: E, index: SizeType.Arr, arr: readonly E[]) => boolean,
@@ -2110,9 +2220,114 @@ export namespace Arr {
2110
2220
  const [array, predicate] = args;
2111
2221
  const foundIndex = array.findIndex(
2112
2222
  // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
2113
- predicate as (value: E, index: number, arr: readonly E[]) => boolean,
2223
+ predicate as () => boolean,
2224
+ );
2225
+
2226
+ expectType<
2227
+ Parameters<typeof array.findIndex>[0],
2228
+ (value: E, index: number, arr: readonly E[]) => unknown
2229
+ >('=');
2230
+
2231
+ expectType<
2232
+ typeof predicate,
2233
+ (value: E, index: SizeType.Arr, arr: readonly E[]) => boolean
2234
+ >('=');
2235
+
2236
+ return foundIndex === -1
2237
+ ? Optional.none
2238
+ : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
2239
+ Optional.some(array[foundIndex]!);
2240
+ }
2241
+ case 1: {
2242
+ const [predicate] = args;
2243
+
2244
+ expectType<
2245
+ typeof predicate,
2246
+ (value: E, index: SizeType.Arr, arr: readonly E[]) => boolean
2247
+ >('=');
2248
+
2249
+ return (array) => find(array, predicate);
2250
+ }
2251
+ }
2252
+ }
2253
+
2254
+ /**
2255
+ * Returns the last element in an array that satisfies a predicate function.
2256
+ *
2257
+ * This function searches from the end of the array and returns an Optional containing
2258
+ * the first element found that satisfies the predicate, or None if no such element exists.
2259
+ *
2260
+ * @template Ar The exact type of the input array.
2261
+ * @template E The type of elements in the array.
2262
+ * @param array The array to search.
2263
+ * @param predicate A function that tests each element.
2264
+ * @returns An Optional containing the found element, or None if no element satisfies the predicate.
2265
+ *
2266
+ * @example
2267
+ * ```typescript
2268
+ * // Direct usage
2269
+ * const numbers = [1, 2, 3, 4, 5];
2270
+ * const lastEven = Arr.findLast(numbers, n => n % 2 === 0); // Optional.some(4)
2271
+ *
2272
+ * // Curried usage
2273
+ * const isPositive = (n: number) => n > 0;
2274
+ * const findLastPositive = Arr.findLast(isPositive);
2275
+ * const result = findLastPositive([-1, 2, -3, 4]); // Optional.some(4)
2276
+ *
2277
+ * // No match
2278
+ * const noMatch = Arr.findLast([1, 3, 5], n => n % 2 === 0); // Optional.none
2279
+ * ```
2280
+ */
2281
+ export function findLast<E, F extends E>(
2282
+ array: readonly E[],
2283
+ predicate: (value: E, index: SizeType.Arr, arr: readonly E[]) => value is F,
2284
+ ): Optional<F>;
2285
+
2286
+ export function findLast<Ar extends readonly unknown[]>(
2287
+ array: Ar,
2288
+ predicate: (value: Ar[number], index: ArrayIndex<Ar>, arr: Ar) => boolean,
2289
+ ): Optional<Ar[number]>;
2290
+
2291
+ export function findLast<E>(
2292
+ predicate: (value: E, index: SizeType.Arr, arr: readonly E[]) => boolean,
2293
+ ): (array: readonly E[]) => Optional<E>;
2294
+
2295
+ export function findLast<E>(
2296
+ ...args:
2297
+ | readonly [
2298
+ array: readonly E[],
2299
+ predicate: (
2300
+ value: E,
2301
+ index: SizeType.Arr,
2302
+ arr: readonly E[],
2303
+ ) => boolean,
2304
+ ]
2305
+ | readonly [
2306
+ predicate: (
2307
+ value: E,
2308
+ index: SizeType.Arr,
2309
+ arr: readonly E[],
2310
+ ) => boolean,
2311
+ ]
2312
+ ): Optional<E> | ((array: readonly E[]) => Optional<E>) {
2313
+ switch (args.length) {
2314
+ case 2: {
2315
+ const [array, predicate] = args;
2316
+ const foundIndex = array.findLastIndex(
2317
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
2318
+ predicate as () => boolean,
2114
2319
  );
2115
2320
 
2321
+ expectType<
2322
+ Parameters<typeof array.findIndex>[0],
2323
+ (value: E, index: number, arr: readonly E[]) => unknown
2324
+ >('=');
2325
+
2326
+ expectType<
2327
+ typeof predicate,
2328
+ (value: E, index: SizeType.Arr, arr: readonly E[]) => boolean
2329
+ >('=');
2330
+
2116
2331
  return foundIndex === -1
2117
2332
  ? Optional.none
2118
2333
  : // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
@@ -2120,7 +2335,13 @@ export namespace Arr {
2120
2335
  }
2121
2336
  case 1: {
2122
2337
  const [predicate] = args;
2123
- return (array: readonly E[]) => find(array, predicate);
2338
+
2339
+ expectType<
2340
+ typeof predicate,
2341
+ (value: E, index: SizeType.Arr, arr: readonly E[]) => boolean
2342
+ >('=');
2343
+
2344
+ return (array) => findLast(array, predicate);
2124
2345
  }
2125
2346
  }
2126
2347
  }
@@ -2230,22 +2451,32 @@ export namespace Arr {
2230
2451
  * @see {@link lastIndexOf} for finding the last occurrence
2231
2452
  * @see {@link Optional} for working with the returned Optional values
2232
2453
  */
2233
- export function findIndex<E>(
2234
- array: readonly E[],
2235
- predicate: (value: E, index: SizeType.Arr) => boolean,
2236
- ): SizeType.Arr | -1;
2454
+ export function findIndex<Ar extends readonly unknown[]>(
2455
+ array: Ar,
2456
+ predicate: (value: Ar[number], index: ArrayIndex<Ar>, arr: Ar) => boolean,
2457
+ ): ArrayIndex<Ar> | -1;
2237
2458
 
2238
2459
  export function findIndex<E>(
2239
- predicate: (value: E, index: SizeType.Arr) => boolean,
2460
+ predicate: (value: E, index: SizeType.Arr, arr: readonly E[]) => boolean,
2240
2461
  ): (array: readonly E[]) => SizeType.Arr | -1;
2241
2462
 
2242
2463
  export function findIndex<E>(
2243
2464
  ...args:
2244
2465
  | readonly [
2245
2466
  array: readonly E[],
2246
- predicate: (value: E, index: SizeType.Arr) => boolean,
2467
+ predicate: (
2468
+ value: E,
2469
+ index: SizeType.Arr,
2470
+ arr: readonly E[],
2471
+ ) => boolean,
2472
+ ]
2473
+ | readonly [
2474
+ predicate: (
2475
+ value: E,
2476
+ index: SizeType.Arr,
2477
+ arr: readonly E[],
2478
+ ) => boolean,
2247
2479
  ]
2248
- | readonly [predicate: (value: E, index: SizeType.Arr) => boolean]
2249
2480
  ): SizeType.Arr | -1 | ((array: readonly E[]) => SizeType.Arr | -1) {
2250
2481
  switch (args.length) {
2251
2482
  case 2: {
@@ -2259,7 +2490,141 @@ export namespace Arr {
2259
2490
  }
2260
2491
  case 1: {
2261
2492
  const [predicate] = args;
2262
- return (array: readonly E[]) => findIndex(array, predicate);
2493
+ return (array) => findIndex(array, predicate);
2494
+ }
2495
+ }
2496
+ }
2497
+
2498
+ /**
2499
+ * Safely finds the index of the last element in an array that satisfies a predicate function.
2500
+ *
2501
+ * This function provides type-safe index searching with no risk of runtime errors. It searches
2502
+ * from the end of the array backwards and returns the index of the last element that matches
2503
+ * the predicate, or -1 if no element is found. The returned index is branded as `SizeType.Arr`
2504
+ * for type safety.
2505
+ *
2506
+ * **Curried Usage:** This function supports currying - when called with only a predicate,
2507
+ * it returns a function that can be applied to arrays, making it ideal for functional composition.
2508
+ *
2509
+ * @template Ar The exact type of the input array, used for precise return type inference.
2510
+ * @template E The type of elements in the array.
2511
+ * @param array The array to search through (when using direct call syntax).
2512
+ * @param predicate A function that tests each element. Called with:
2513
+ * - `value`: The current element being tested
2514
+ * - `index`: The index of the current element (branded as `SizeType.Arr`)
2515
+ * - `arr`: The array being searched
2516
+ * @returns The index of the last matching element as `SizeType.Arr`, or -1 if no element satisfies the predicate.
2517
+ *
2518
+ * @example
2519
+ * ```typescript
2520
+ * // Basic last index finding
2521
+ * const fruits = ['apple', 'banana', 'cherry', 'banana'];
2522
+ * const lastBananaIndex = Arr.findLastIndex(fruits, fruit => fruit === 'banana');
2523
+ * console.log(lastBananaIndex); // 3 - index of last 'banana'
2524
+ *
2525
+ * // Finding with complex conditions
2526
+ * const numbers = [1, 5, 10, 15, 20, 10, 5];
2527
+ * const lastLargeIndex = Arr.findLastIndex(numbers, (value, index) =>
2528
+ * value > 8 && index < 5
2529
+ * );
2530
+ * console.log(lastLargeIndex); // 3 - index of last value > 8 before index 5 (15)
2531
+ *
2532
+ * // Finding objects by property
2533
+ * const users = [
2534
+ * { id: 1, active: true },
2535
+ * { id: 2, active: false },
2536
+ * { id: 3, active: true },
2537
+ * { id: 4, active: false }
2538
+ * ];
2539
+ *
2540
+ * const lastActiveIndex = Arr.findLastIndex(users, user => user.active);
2541
+ * console.log(lastActiveIndex); // 2 - index of last active user
2542
+ *
2543
+ * const lastInactiveIndex = Arr.findLastIndex(users, user => !user.active);
2544
+ * console.log(lastInactiveIndex); // 3 - index of last inactive user
2545
+ *
2546
+ * // Empty array handling
2547
+ * const emptyResult = Arr.findLastIndex([], (x: number) => x > 0); // -1
2548
+ *
2549
+ * // Curried usage for functional composition
2550
+ * const findLastNegativeIndex = Arr.findLastIndex((x: number) => x < 0);
2551
+ * const findLastLongStringIndex = Arr.findLastIndex((s: string) => s.length > 5);
2552
+ *
2553
+ * const datasets = [
2554
+ * [1, 2, -3, 4, -5], // last negative at index 4
2555
+ * [5, 6, 7, 8], // no negative
2556
+ * [-1, 0, 1, -2] // last negative at index 3
2557
+ * ];
2558
+ *
2559
+ * const lastNegativeIndices = datasets.map(findLastNegativeIndex);
2560
+ * // [4, -1, 3]
2561
+ *
2562
+ * // Functional composition
2563
+ * const data = ['short', 'medium', 'very long string', 'tiny', 'another long one'];
2564
+ * const lastLongIndex = Arr.findLastIndex(data, s => s.length > 8);
2565
+ * console.log(lastLongIndex); // 4 - index of 'another long one'
2566
+ *
2567
+ * // Using with pipe
2568
+ * const result = pipe(['a', 'bb', 'ccc', 'bb'])
2569
+ * .map(Arr.findLastIndex((s: string) => s.length === 2))
2570
+ * .value; // 3 (last occurrence of 'bb')
2571
+ *
2572
+ * // Comparing with findIndex
2573
+ * const values = [1, 2, 3, 2, 4];
2574
+ * const firstTwo = Arr.findIndex(values, x => x === 2); // 1
2575
+ * const lastTwo = Arr.findLastIndex(values, x => x === 2); // 3
2576
+ *
2577
+ * // Type safety with tuples
2578
+ * const tuple = [10, 20, 30, 20] as const;
2579
+ * const lastTwentyIndex = Arr.findLastIndex(tuple, x => x === 20);
2580
+ * // Type: ArrayIndex<readonly [10, 20, 30, 20]> | -1
2581
+ * // Value: 3
2582
+ * ```
2583
+ *
2584
+ * @see {@link findLast} for finding the element instead of its index
2585
+ * @see {@link findIndex} for finding the first occurrence
2586
+ * @see {@link lastIndexOf} for finding elements by equality (not predicate)
2587
+ */
2588
+ export function findLastIndex<Ar extends readonly unknown[]>(
2589
+ array: Ar,
2590
+ predicate: (value: Ar[number], index: ArrayIndex<Ar>, arr: Ar) => boolean,
2591
+ ): ArrayIndex<Ar> | -1;
2592
+
2593
+ export function findLastIndex<E>(
2594
+ predicate: (value: E, index: SizeType.Arr, arr: readonly E[]) => boolean,
2595
+ ): (array: readonly E[]) => SizeType.Arr | -1;
2596
+
2597
+ export function findLastIndex<E>(
2598
+ ...args:
2599
+ | readonly [
2600
+ array: readonly E[],
2601
+ predicate: (
2602
+ value: E,
2603
+ index: SizeType.Arr,
2604
+ arr: readonly E[],
2605
+ ) => boolean,
2606
+ ]
2607
+ | readonly [
2608
+ predicate: (
2609
+ value: E,
2610
+ index: SizeType.Arr,
2611
+ arr: readonly E[],
2612
+ ) => boolean,
2613
+ ]
2614
+ ): SizeType.Arr | -1 | ((array: readonly E[]) => SizeType.Arr | -1) {
2615
+ switch (args.length) {
2616
+ case 2: {
2617
+ const [array, predicate] = args;
2618
+ return pipe(
2619
+ array.findLastIndex(
2620
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
2621
+ predicate as (value: E, index: number) => boolean,
2622
+ ),
2623
+ ).map((idx) => (idx >= 0 ? asUint32(idx) : -1)).value;
2624
+ }
2625
+ case 1: {
2626
+ const [predicate] = args;
2627
+ return (array) => findLastIndex(array, predicate);
2263
2628
  }
2264
2629
  }
2265
2630
  }
@@ -2285,10 +2650,10 @@ export namespace Arr {
2285
2650
  * console.log(Optional.unwrapOr(result2, -1)); // 1
2286
2651
  * ```
2287
2652
  */
2288
- export function indexOf<E>(
2289
- array: readonly E[],
2290
- searchElement: E,
2291
- ): SizeType.Arr | -1;
2653
+ export function indexOf<Ar extends readonly unknown[]>(
2654
+ array: Ar,
2655
+ searchElement: Ar[number],
2656
+ ): ArrayIndex<Ar> | -1;
2292
2657
 
2293
2658
  export function indexOf<E>(
2294
2659
  searchElement: E,
@@ -2308,20 +2673,20 @@ export namespace Arr {
2308
2673
  }
2309
2674
  case 1: {
2310
2675
  const [searchElement] = args;
2311
- return (array: readonly E[]) => indexOf(array, searchElement);
2676
+ return (array) => indexOf(array, searchElement);
2312
2677
  }
2313
2678
  }
2314
2679
  }
2315
2680
 
2316
- export function indexOfFrom<E>(
2317
- array: readonly E[],
2318
- searchElement: E,
2319
- fromIndex: SizeType.ArgArr,
2320
- ): SizeType.Arr | -1;
2681
+ export function indexOfFrom<Ar extends readonly unknown[]>(
2682
+ array: Ar,
2683
+ searchElement: Ar[number],
2684
+ fromIndex: ArgArrayIndexWithNegative<Ar>,
2685
+ ): ArrayIndex<Ar> | -1;
2321
2686
 
2322
2687
  export function indexOfFrom<E>(
2323
2688
  searchElement: E,
2324
- fromIndex: SizeType.ArgArr,
2689
+ fromIndex: SizeType.ArgArrWithNegative,
2325
2690
  ): (array: readonly E[]) => SizeType.Arr | -1;
2326
2691
 
2327
2692
  export function indexOfFrom<E>(
@@ -2329,9 +2694,9 @@ export namespace Arr {
2329
2694
  | readonly [
2330
2695
  array: readonly E[],
2331
2696
  searchElement: E,
2332
- fromIndex: SizeType.ArgArr,
2697
+ fromIndex: SizeType.ArgArrWithNegative,
2333
2698
  ]
2334
- | readonly [searchElement: E, fromIndex: SizeType.ArgArr]
2699
+ | readonly [searchElement: E, fromIndex: SizeType.ArgArrWithNegative]
2335
2700
  ): SizeType.Arr | -1 | ((array: readonly E[]) => SizeType.Arr | -1) {
2336
2701
  switch (args.length) {
2337
2702
  case 3: {
@@ -2341,8 +2706,7 @@ export namespace Arr {
2341
2706
  }
2342
2707
  case 2: {
2343
2708
  const [searchElement, fromIndex] = args;
2344
- return (array: readonly E[]) =>
2345
- indexOfFrom(array, searchElement, fromIndex);
2709
+ return (array) => indexOfFrom(array, searchElement, fromIndex);
2346
2710
  }
2347
2711
  }
2348
2712
  }
@@ -2368,10 +2732,10 @@ export namespace Arr {
2368
2732
  * console.log(Optional.unwrapOr(result2, -1)); // 3
2369
2733
  * ```
2370
2734
  */
2371
- export function lastIndexOf<E>(
2372
- array: readonly E[],
2373
- searchElement: E,
2374
- ): SizeType.Arr | -1;
2735
+ export function lastIndexOf<Ar extends readonly unknown[]>(
2736
+ array: Ar,
2737
+ searchElement: Ar[number],
2738
+ ): ArrayIndex<Ar> | -1;
2375
2739
 
2376
2740
  export function lastIndexOf<E>(
2377
2741
  searchElement: E,
@@ -2390,20 +2754,20 @@ export namespace Arr {
2390
2754
  }
2391
2755
  case 1: {
2392
2756
  const [searchElement] = args;
2393
- return (array: readonly E[]) => lastIndexOf(array, searchElement);
2757
+ return (array) => lastIndexOf(array, searchElement);
2394
2758
  }
2395
2759
  }
2396
2760
  }
2397
2761
 
2398
- export function lastIndexOfFrom<E>(
2399
- array: readonly E[],
2400
- searchElement: E,
2401
- fromIndex: SizeType.ArgArr,
2402
- ): SizeType.Arr | -1;
2762
+ export function lastIndexOfFrom<Ar extends readonly unknown[]>(
2763
+ array: Ar,
2764
+ searchElement: Ar[number],
2765
+ fromIndex: ArgArrayIndexWithNegative<Ar>,
2766
+ ): ArrayIndex<Ar> | -1;
2403
2767
 
2404
2768
  export function lastIndexOfFrom<E>(
2405
2769
  searchElement: E,
2406
- fromIndex: SizeType.ArgArr,
2770
+ fromIndex: SizeType.ArgArrWithNegative,
2407
2771
  ): (array: readonly E[]) => SizeType.Arr | -1;
2408
2772
 
2409
2773
  export function lastIndexOfFrom<E>(
@@ -2411,9 +2775,9 @@ export namespace Arr {
2411
2775
  | readonly [
2412
2776
  array: readonly E[],
2413
2777
  searchElement: E,
2414
- fromIndex: SizeType.ArgArr,
2778
+ fromIndex: SizeType.ArgArrWithNegative,
2415
2779
  ]
2416
- | readonly [searchElement: E, fromIndex: SizeType.ArgArr]
2780
+ | readonly [searchElement: E, fromIndex: SizeType.ArgArrWithNegative]
2417
2781
  ): SizeType.Arr | -1 | ((array: readonly E[]) => SizeType.Arr | -1) {
2418
2782
  switch (args.length) {
2419
2783
  case 3: {
@@ -2425,8 +2789,145 @@ export namespace Arr {
2425
2789
  }
2426
2790
  case 2: {
2427
2791
  const [searchElement, fromIndex] = args;
2428
- return (array: readonly E[]) =>
2429
- lastIndexOfFrom(array, searchElement, fromIndex);
2792
+ return (array) => lastIndexOfFrom(array, searchElement, fromIndex);
2793
+ }
2794
+ }
2795
+ }
2796
+
2797
+ /**
2798
+ * Tests whether all elements in an array pass a test implemented by a predicate function.
2799
+ *
2800
+ * This function returns `true` if all elements satisfy the predicate, `false` otherwise.
2801
+ * For empty arrays, it returns `true` (vacuous truth).
2802
+ * Supports type guard predicates for type narrowing of the entire array.
2803
+ *
2804
+ * @template Ar The exact type of the input array.
2805
+ * @template E The type of elements in the array.
2806
+ * @template S The narrowed type when using type guard predicates.
2807
+ * @param array The array to test.
2808
+ * @param predicate A function that tests each element.
2809
+ * @returns `true` if all elements pass the test, `false` otherwise.
2810
+ *
2811
+ * @example
2812
+ * ```typescript
2813
+ * // Direct usage
2814
+ * const numbers = [2, 4, 6, 8];
2815
+ * const allEven = Arr.every(numbers, n => n % 2 === 0); // true
2816
+ *
2817
+ * // Type guard usage - narrows entire array type
2818
+ * const mixed: (string | number)[] = ['hello', 'world'];
2819
+ * if (Arr.every(mixed, (x): x is string => typeof x === 'string')) {
2820
+ * // TypeScript knows mixed is string[] here
2821
+ * console.log(mixed.map(s => s.toUpperCase()));
2822
+ * }
2823
+ *
2824
+ * // Curried usage with type guards
2825
+ * const isString = (x: unknown): x is string => typeof x === 'string';
2826
+ * const allStrings = Arr.every(isString);
2827
+ * const data: unknown[] = ['a', 'b', 'c'];
2828
+ * if (allStrings(data)) {
2829
+ * // TypeScript knows data is string[] here
2830
+ * console.log(data.join(''));
2831
+ * }
2832
+ *
2833
+ * // Empty array
2834
+ * const empty: number[] = [];
2835
+ * const result2 = Arr.every(empty, n => n > 0); // true
2836
+ * ```
2837
+ */
2838
+ // Type guard overloads - narrow the entire array type
2839
+ export function every<E, S extends E>(
2840
+ array: readonly E[],
2841
+ predicate: (a: E, index: SizeType.Arr) => a is S,
2842
+ ): array is readonly S[];
2843
+
2844
+ export function every<E, S extends E>(
2845
+ predicate: (a: E, index: SizeType.Arr) => a is S,
2846
+ ): (array: readonly E[]) => array is readonly S[];
2847
+
2848
+ // Regular boolean predicate overloads
2849
+ export function every<Ar extends readonly unknown[]>(
2850
+ array: Ar,
2851
+ predicate: (a: Ar[number], index: ArrayIndex<Ar>) => boolean,
2852
+ ): boolean;
2853
+
2854
+ export function every<E>(
2855
+ predicate: (a: E, index: SizeType.Arr) => boolean,
2856
+ ): (array: readonly E[]) => boolean;
2857
+
2858
+ export function every<E>(
2859
+ ...args:
2860
+ | readonly [
2861
+ array: readonly E[],
2862
+ predicate: (a: E, index: SizeType.Arr) => boolean,
2863
+ ]
2864
+ | readonly [predicate: (a: E, index: SizeType.Arr) => boolean]
2865
+ ): boolean | ((array: readonly E[]) => boolean) {
2866
+ switch (args.length) {
2867
+ case 2: {
2868
+ const [array, predicate] = args;
2869
+ return array.every((a, i) => predicate(a, asUint32(i)));
2870
+ }
2871
+ case 1: {
2872
+ const [predicate] = args;
2873
+ return (array) => every(array, predicate);
2874
+ }
2875
+ }
2876
+ }
2877
+
2878
+ /**
2879
+ * Tests whether at least one element in an array passes a test implemented by a predicate function.
2880
+ *
2881
+ * This function returns `true` if at least one element satisfies the predicate, `false` otherwise.
2882
+ * For empty arrays, it returns `false`.
2883
+ *
2884
+ * @template Ar The exact type of the input array.
2885
+ * @template E The type of elements in the array.
2886
+ * @param array The array to test.
2887
+ * @param predicate A function that tests each element.
2888
+ * @returns `true` if at least one element passes the test, `false` otherwise.
2889
+ *
2890
+ * @example
2891
+ * ```typescript
2892
+ * // Direct usage
2893
+ * const numbers = [1, 3, 5, 8];
2894
+ * const hasEven = Arr.some(numbers, n => n % 2 === 0); // true
2895
+ *
2896
+ * // Curried usage
2897
+ * const isNegative = (n: number) => n < 0;
2898
+ * const hasNegative = Arr.some(isNegative);
2899
+ * const result = hasNegative([1, 2, -3]); // true
2900
+ *
2901
+ * // Empty array
2902
+ * const empty: number[] = [];
2903
+ * const result2 = Arr.some(empty, n => n > 0); // false
2904
+ * ```
2905
+ */
2906
+ export function some<Ar extends readonly unknown[]>(
2907
+ array: Ar,
2908
+ predicate: (a: Ar[number], index: ArrayIndex<Ar>) => boolean,
2909
+ ): boolean;
2910
+
2911
+ export function some<E>(
2912
+ predicate: (a: E, index: SizeType.Arr) => boolean,
2913
+ ): (array: readonly E[]) => boolean;
2914
+
2915
+ export function some<E>(
2916
+ ...args:
2917
+ | readonly [
2918
+ array: readonly E[],
2919
+ predicate: (a: E, index: SizeType.Arr) => boolean,
2920
+ ]
2921
+ | readonly [predicate: (a: E, index: SizeType.Arr) => boolean]
2922
+ ): boolean | ((array: readonly E[]) => boolean) {
2923
+ switch (args.length) {
2924
+ case 2: {
2925
+ const [array, predicate] = args;
2926
+ return array.some((a, i) => predicate(a, asUint32(i)));
2927
+ }
2928
+ case 1: {
2929
+ const [predicate] = args;
2930
+ return (array) => some(array, predicate);
2430
2931
  }
2431
2932
  }
2432
2933
  }
@@ -2448,12 +2949,12 @@ export namespace Arr {
2448
2949
  * Arr.foldl(['a', 'b', 'c'], (acc, str) => acc + str.toUpperCase(), ''); // 'ABC'
2449
2950
  * ```
2450
2951
  */
2451
- export function foldl<E, P>(
2452
- array: readonly E[],
2952
+ export function foldl<Ar extends readonly unknown[], P>(
2953
+ array: Ar,
2453
2954
  callbackfn: (
2454
2955
  previousValue: P,
2455
- currentValue: E,
2456
- currentIndex: SizeType.Arr,
2956
+ currentValue: Ar[number],
2957
+ currentIndex: ArrayIndex<Ar>,
2457
2958
  ) => P,
2458
2959
  initialValue: P,
2459
2960
  ): P;
@@ -2497,7 +2998,7 @@ export namespace Arr {
2497
2998
  }
2498
2999
  case 2: {
2499
3000
  const [callbackfn, initialValue] = args;
2500
- return (array: readonly E[]) => foldl(array, callbackfn, initialValue);
3001
+ return (array) => foldl(array, callbackfn, initialValue);
2501
3002
  }
2502
3003
  }
2503
3004
  }
@@ -2522,12 +3023,12 @@ export namespace Arr {
2522
3023
  * console.log(result); // "abc"
2523
3024
  * ```
2524
3025
  */
2525
- export function foldr<E, P>(
2526
- array: readonly E[],
3026
+ export function foldr<Ar extends readonly unknown[], P>(
3027
+ array: Ar,
2527
3028
  callbackfn: (
2528
3029
  previousValue: P,
2529
- currentValue: E,
2530
- currentIndex: SizeType.Arr,
3030
+ currentValue: Ar[number],
3031
+ currentIndex: ArrayIndex<Ar>,
2531
3032
  ) => P,
2532
3033
  initialValue: P,
2533
3034
  ): P;
@@ -2571,7 +3072,7 @@ export namespace Arr {
2571
3072
  }
2572
3073
  case 2: {
2573
3074
  const [callbackfn, initialValue] = args;
2574
- return (array: readonly E[]) => foldr(array, callbackfn, initialValue);
3075
+ return (array) => foldr(array, callbackfn, initialValue);
2575
3076
  }
2576
3077
  }
2577
3078
  }
@@ -2589,25 +3090,20 @@ export namespace Arr {
2589
3090
  * Arr.min([]); // Optional.none
2590
3091
  * ```
2591
3092
  */
2592
- export function min<E extends number>(
2593
- array: NonEmptyArray<E>,
2594
- comparator?: (x: E, y: E) => number,
2595
- ): Optional.Some<E>;
2596
-
2597
- export function min<E extends number>(
2598
- array: readonly E[],
2599
- comparator?: (x: E, y: E) => number,
2600
- ): Optional<E>;
2601
-
2602
- export function min<E>(
2603
- array: NonEmptyArray<E>,
2604
- comparator: (x: E, y: E) => number,
2605
- ): Optional.Some<E>;
3093
+ export function min<Ar extends readonly number[]>(
3094
+ array: Ar,
3095
+ // If the array elements are numbers, comparator is optional.
3096
+ comparator?: (x: Ar[number], y: Ar[number]) => number,
3097
+ ): Ar extends NonEmptyArray<unknown>
3098
+ ? Optional.Some<Ar[number]>
3099
+ : Optional<Ar[number]>;
2606
3100
 
2607
- export function min<E>(
2608
- array: readonly E[],
2609
- comparator: (x: E, y: E) => number,
2610
- ): Optional<E>;
3101
+ export function min<Ar extends readonly unknown[]>(
3102
+ array: Ar,
3103
+ comparator: (x: Ar[number], y: Ar[number]) => number,
3104
+ ): Ar extends NonEmptyArray<unknown>
3105
+ ? Optional.Some<Ar[number]>
3106
+ : Optional<Ar[number]>;
2611
3107
 
2612
3108
  export function min<E extends number>(
2613
3109
  array: readonly E[],
@@ -2645,25 +3141,20 @@ export namespace Arr {
2645
3141
  * Arr.max([]); // Optional.none
2646
3142
  * ```
2647
3143
  */
2648
- export function max<E extends number>(
2649
- array: NonEmptyArray<E>,
2650
- comparator?: (x: E, y: E) => number,
2651
- ): Optional.Some<E>;
2652
-
2653
- export function max<E extends number>(
2654
- array: readonly E[],
2655
- comparator?: (x: E, y: E) => number,
2656
- ): Optional<E>;
2657
-
2658
- export function max<E>(
2659
- array: NonEmptyArray<E>,
2660
- comparator: (x: E, y: E) => number,
2661
- ): Optional.Some<E>;
3144
+ export function max<Ar extends readonly number[]>(
3145
+ array: Ar,
3146
+ // If the array elements are numbers, comparator is optional.
3147
+ comparator?: (x: Ar[number], y: Ar[number]) => number,
3148
+ ): Ar extends NonEmptyArray<unknown>
3149
+ ? Optional.Some<Ar[number]>
3150
+ : Optional<Ar[number]>;
2662
3151
 
2663
- export function max<E>(
2664
- array: readonly E[],
2665
- comparator: (x: E, y: E) => number,
2666
- ): Optional<E>;
3152
+ export function max<Ar extends readonly unknown[]>(
3153
+ array: Ar,
3154
+ comparator: (x: Ar[number], y: Ar[number]) => number,
3155
+ ): Ar extends NonEmptyArray<unknown>
3156
+ ? Optional.Some<Ar[number]>
3157
+ : Optional<Ar[number]>;
2667
3158
 
2668
3159
  export function max<E extends number>(
2669
3160
  array: readonly E[],
@@ -2694,27 +3185,21 @@ export namespace Arr {
2694
3185
  * Arr.minBy([], p => p.age); // Optional.none
2695
3186
  * ```
2696
3187
  */
2697
- export function minBy<E>(
2698
- array: NonEmptyArray<E>,
2699
- comparatorValueMapper: (value: E) => number,
2700
- ): Optional.Some<E>;
2701
-
2702
- export function minBy<E>(
2703
- array: readonly E[],
2704
- comparatorValueMapper: (value: E) => number,
2705
- ): Optional<E>;
2706
-
2707
- export function minBy<E, V>(
2708
- array: NonEmptyArray<E>,
2709
- comparatorValueMapper: (value: E) => V,
2710
- comparator: (x: V, y: V) => number,
2711
- ): Optional.Some<E>;
3188
+ export function minBy<Ar extends readonly unknown[]>(
3189
+ array: Ar,
3190
+ // If the array elements are mapped to numbers, comparator is optional.
3191
+ comparatorValueMapper: (value: Ar[number]) => number,
3192
+ ): Ar extends NonEmptyArray<unknown>
3193
+ ? Optional.Some<Ar[number]>
3194
+ : Optional<Ar[number]>;
2712
3195
 
2713
- export function minBy<E, V>(
2714
- array: readonly E[],
2715
- comparatorValueMapper: (value: E) => V,
3196
+ export function minBy<Ar extends readonly unknown[], V>(
3197
+ array: Ar,
3198
+ comparatorValueMapper: (value: Ar[number]) => V,
2716
3199
  comparator: (x: V, y: V) => number,
2717
- ): Optional<E>;
3200
+ ): Ar extends NonEmptyArray<unknown>
3201
+ ? Optional.Some<Ar[number]>
3202
+ : Optional<Ar[number]>;
2718
3203
 
2719
3204
  export function minBy<E, V>(
2720
3205
  array: readonly E[],
@@ -2749,27 +3234,21 @@ export namespace Arr {
2749
3234
  * Arr.maxBy([], p => p.age); // Optional.none
2750
3235
  * ```
2751
3236
  */
2752
- export function maxBy<E>(
2753
- array: NonEmptyArray<E>,
2754
- comparatorValueMapper: (value: E) => number,
2755
- ): Optional.Some<E>;
2756
-
2757
- export function maxBy<E>(
2758
- array: readonly E[],
2759
- comparatorValueMapper: (value: E) => number,
2760
- ): Optional<E>;
2761
-
2762
- export function maxBy<E, V>(
2763
- array: NonEmptyArray<E>,
2764
- comparatorValueMapper: (value: E) => V,
2765
- comparator: (x: V, y: V) => number,
2766
- ): Optional.Some<E>;
3237
+ export function maxBy<Ar extends readonly unknown[]>(
3238
+ array: Ar,
3239
+ // If the array elements are mapped to numbers, comparator is optional.
3240
+ comparatorValueMapper: (value: Ar[number]) => number,
3241
+ ): Ar extends NonEmptyArray<unknown>
3242
+ ? Optional.Some<Ar[number]>
3243
+ : Optional<Ar[number]>;
2767
3244
 
2768
- export function maxBy<E, V>(
2769
- array: readonly E[],
2770
- comparatorValueMapper: (value: E) => V,
3245
+ export function maxBy<Ar extends readonly unknown[], V>(
3246
+ array: Ar,
3247
+ comparatorValueMapper: (value: Ar[number]) => V,
2771
3248
  comparator: (x: V, y: V) => number,
2772
- ): Optional<E>;
3249
+ ): Ar extends NonEmptyArray<unknown>
3250
+ ? Optional.Some<Ar[number]>
3251
+ : Optional<Ar[number]>;
2773
3252
 
2774
3253
  export function maxBy<E, V>(
2775
3254
  array: readonly E[],
@@ -2801,9 +3280,9 @@ export namespace Arr {
2801
3280
  * console.log(result); // 3
2802
3281
  * ```
2803
3282
  */
2804
- export function count<E>(
2805
- array: readonly E[],
2806
- predicate: (value: E, index: SizeType.Arr) => boolean,
3283
+ export function count<Ar extends readonly unknown[]>(
3284
+ array: Ar,
3285
+ predicate: (value: Ar[number], index: ArrayIndex<Ar>) => boolean,
2807
3286
  ): SizeType.Arr;
2808
3287
 
2809
3288
  export function count<E>(
@@ -2829,7 +3308,7 @@ export namespace Arr {
2829
3308
  }
2830
3309
  case 1: {
2831
3310
  const [predicate] = args;
2832
- return (array: readonly E[]) => count(array, predicate);
3311
+ return (array) => count(array, predicate);
2833
3312
  }
2834
3313
  }
2835
3314
  }
@@ -2854,10 +3333,13 @@ export namespace Arr {
2854
3333
  * // IMap { 'a' => 2, 'b' => 1 }
2855
3334
  * ```
2856
3335
  */
2857
- export function countBy<E, G extends MapSetKeyType>(
2858
- array: readonly E[],
2859
- grouper: (value: E, index: SizeType.Arr) => G,
2860
- ): IMap<G, SizeType.Arr>;
3336
+ export function countBy<
3337
+ Ar extends readonly unknown[],
3338
+ G extends MapSetKeyType,
3339
+ >(
3340
+ array: Ar,
3341
+ grouper: (value: Ar[number], index: ArrayIndex<Ar>) => G,
3342
+ ): IMap<G, ArrayIndex<Ar>>;
2861
3343
 
2862
3344
  export function countBy<E, G extends MapSetKeyType>(
2863
3345
  grouper: (value: E, index: SizeType.Arr) => G,
@@ -2887,7 +3369,7 @@ export namespace Arr {
2887
3369
  }
2888
3370
  case 1: {
2889
3371
  const [grouper] = args;
2890
- return (array: readonly E[]) => countBy(array, grouper);
3372
+ return (array) => countBy(array, grouper);
2891
3373
  }
2892
3374
  }
2893
3375
  }
@@ -2953,12 +3435,12 @@ export namespace Arr {
2953
3435
  ): Result<string, Error> | ((array: readonly E[]) => Result<string, Error>) {
2954
3436
  switch (args.length) {
2955
3437
  case 0:
2956
- return (array: readonly E[]) => joinImpl(array, undefined);
3438
+ return (array) => joinImpl(array, undefined);
2957
3439
 
2958
3440
  case 1: {
2959
3441
  const [arg] = args;
2960
3442
  if (isString(arg) || isUndefined(arg)) {
2961
- return (array: readonly E[]) => joinImpl(array, arg);
3443
+ return (array) => joinImpl(array, arg);
2962
3444
  }
2963
3445
  return joinImpl(arg, undefined);
2964
3446
  }
@@ -3019,6 +3501,145 @@ export namespace Arr {
3019
3501
  tp(array1[i]!, array2[i]!),
3020
3502
  ) as unknown as List.Zip<Ar1, Ar2>;
3021
3503
 
3504
+ /**
3505
+ * Creates a new tuple by transforming each element with a mapping function.
3506
+ *
3507
+ * Preserves the tuple's length while allowing element type transformation.
3508
+ * The resulting tuple has the same structure but with transformed element types.
3509
+ *
3510
+ * @template T - The type of the input tuple
3511
+ * @template B - The type that elements will be transformed to
3512
+ * @param array - The input tuple
3513
+ * @param mapFn - Function that transforms each element (receives element and index)
3514
+ * @returns A new tuple with transformed elements, preserving the original length
3515
+ *
3516
+ * @example
3517
+ * ```typescript
3518
+ * // Basic transformation
3519
+ * const nums = [1, 2, 3] as const;
3520
+ * const doubled = Arr.map(nums, (x) => x * 2); // readonly [2, 4, 6]
3521
+ * const strings = Arr.map(nums, (x) => String(x)); // readonly ['1', '2', '3']
3522
+ *
3523
+ * // With index
3524
+ * const indexed = Arr.map(nums, (x, i) => `${i}:${x}`);
3525
+ * // readonly ['0:1', '1:2', '2:3']
3526
+ *
3527
+ * // Mixed type tuples
3528
+ * const mixed = [1, 'hello', true] as const;
3529
+ * const descriptions = Arr.map(mixed, (x) => `Value: ${x}`);
3530
+ * // readonly ['Value: 1', 'Value: hello', 'Value: true']
3531
+ * ```
3532
+ */
3533
+ export function map<const Ar extends readonly unknown[], B>(
3534
+ array: Ar,
3535
+ mapFn: (a: Ar[number], index: ArrayIndex<Ar>) => B,
3536
+ ): Readonly<{ [K in keyof Ar]: B }>;
3537
+
3538
+ // curried version
3539
+ export function map<A, B>(
3540
+ mapFn: (a: A, index: SizeType.Arr) => B,
3541
+ ): <Ar extends readonly A[]>(array: Ar) => Readonly<{ [K in keyof Ar]: B }>;
3542
+
3543
+ export function map<A, B>(
3544
+ ...args:
3545
+ | readonly [array: readonly A[], mapFn: (a: A, index: SizeType.Arr) => B]
3546
+ | readonly [mapFn: (a: A, index: SizeType.Arr) => B]
3547
+ ): readonly B[] | ((array: readonly A[]) => readonly B[]) {
3548
+ switch (args.length) {
3549
+ case 2: {
3550
+ const [array, mapFn] = args;
3551
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
3552
+ return array.map(mapFn as never);
3553
+ }
3554
+ case 1: {
3555
+ const [mapFn] = args;
3556
+ return (array: readonly A[]) => map(array, mapFn);
3557
+ }
3558
+ }
3559
+ }
3560
+
3561
+ /**
3562
+ * Filters an array based on a predicate function.
3563
+ *
3564
+ * This function returns a new array containing only the elements that satisfy the predicate.
3565
+ * It provides both direct usage and curried versions for functional composition.
3566
+ * Supports type guard predicates for type narrowing.
3567
+ *
3568
+ * @template Ar The exact type of the input array, used for precise return type inference.
3569
+ * @template E The type of elements in the array.
3570
+ * @template S The narrowed type when using type guard predicates.
3571
+ * @param array The array to filter.
3572
+ * @param predicate A function that tests each element. Returns `true` to keep the element, `false` to filter it out.
3573
+ * @returns A new array containing only the elements that satisfy the predicate.
3574
+ *
3575
+ * @example
3576
+ * ```typescript
3577
+ * // Direct usage
3578
+ * const numbers = [1, 2, 3, 4, 5];
3579
+ * const evens = Arr.filter(numbers, n => n % 2 === 0); // [2, 4]
3580
+ *
3581
+ * // Type guard usage
3582
+ * const mixed: (string | number | null)[] = ['hello', 42, null, 'world'];
3583
+ * const strings = Arr.filter(mixed, (x): x is string => typeof x === 'string'); // string[]
3584
+ * const notNull = Arr.filter(mixed, (x): x is NonNullable<typeof x> => x != null); // (string | number)[]
3585
+ *
3586
+ * // Curried usage with type guards
3587
+ * const isString = (x: unknown): x is string => typeof x === 'string';
3588
+ * const filterStrings = Arr.filter(isString);
3589
+ * const result = filterStrings(['a', 1, 'b', 2]); // string[]
3590
+ *
3591
+ * // Functional composition
3592
+ * const processNumbers = pipe(
3593
+ * Arr.filter((n: number) => n > 0),
3594
+ * Arr.map(n => n * 2)
3595
+ * );
3596
+ * ```
3597
+ *
3598
+ * @see {@link filterNot} for filtering with negated predicate
3599
+ * @see {@link every} for testing if all elements satisfy a predicate
3600
+ * @see {@link some} for testing if any elements satisfy a predicate
3601
+ * @see {@link find} for finding the first element that satisfies a predicate
3602
+ */
3603
+ // Type guard overloads
3604
+ export function filter<Ar extends readonly unknown[], S extends Ar[number]>(
3605
+ array: Ar,
3606
+ predicate: (a: Ar[number], index: ArrayIndex<Ar>) => a is S,
3607
+ ): readonly S[];
3608
+
3609
+ export function filter<E, S extends E>(
3610
+ predicate: (a: E, index: SizeType.Arr) => a is S,
3611
+ ): (array: readonly E[]) => readonly S[];
3612
+
3613
+ // Regular boolean predicate overloads
3614
+ export function filter<Ar extends readonly unknown[]>(
3615
+ array: Ar,
3616
+ predicate: (a: Ar[number], index: ArrayIndex<Ar>) => boolean,
3617
+ ): readonly Ar[number][];
3618
+
3619
+ export function filter<E>(
3620
+ predicate: (a: E, index: SizeType.Arr) => boolean,
3621
+ ): (array: readonly E[]) => readonly E[];
3622
+
3623
+ export function filter<E>(
3624
+ ...args:
3625
+ | readonly [
3626
+ array: readonly E[],
3627
+ predicate: (a: E, index: SizeType.Arr) => boolean,
3628
+ ]
3629
+ | readonly [predicate: (a: E, index: SizeType.Arr) => boolean]
3630
+ ): readonly E[] | ((array: readonly E[]) => readonly E[]) {
3631
+ switch (args.length) {
3632
+ case 2: {
3633
+ const [array, predicate] = args;
3634
+ return array.filter((a, i) => predicate(a, asUint32(i)));
3635
+ }
3636
+ case 1: {
3637
+ const [predicate] = args;
3638
+ return (array) => filter(array, predicate);
3639
+ }
3640
+ }
3641
+ }
3642
+
3022
3643
  /**
3023
3644
  * Filters an array by excluding elements for which the predicate returns true.
3024
3645
  * This is the opposite of `Array.prototype.filter`.
@@ -3037,10 +3658,10 @@ export namespace Arr {
3037
3658
  * console.log(result); // [1, 3, 5]
3038
3659
  * ```
3039
3660
  */
3040
- export function filterNot<E>(
3041
- array: readonly E[],
3042
- predicate: (a: E, index: SizeType.Arr) => boolean,
3043
- ): readonly E[];
3661
+ export function filterNot<Ar extends readonly unknown[]>(
3662
+ array: Ar,
3663
+ predicate: (a: Ar[number], index: ArrayIndex<Ar>) => boolean,
3664
+ ): readonly Ar[number][];
3044
3665
 
3045
3666
  export function filterNot<E>(
3046
3667
  predicate: (a: E, index: SizeType.Arr) => boolean,
@@ -3061,7 +3682,127 @@ export namespace Arr {
3061
3682
  }
3062
3683
  case 1: {
3063
3684
  const [predicate] = args;
3064
- return (array: readonly E[]) => filterNot(array, predicate);
3685
+ return (array) => filterNot(array, predicate);
3686
+ }
3687
+ }
3688
+ }
3689
+
3690
+ /**
3691
+ * Creates a new array with all sub-array elements concatenated into it recursively up to the specified depth.
3692
+ *
3693
+ * This function flattens nested arrays to the specified depth level.
3694
+ * A depth of 1 flattens one level, Number.POSITIVE_INFINITY flattens all levels.
3695
+ *
3696
+ * @template Ar The exact type of the input array.
3697
+ * @template D The depth of flattening.
3698
+ * @param array The array to flatten.
3699
+ * @param depth The depth level specifying how deep a nested array structure should be flattened.
3700
+ * @returns A new array with the sub-array elements concatenated.
3701
+ *
3702
+ * @example
3703
+ * ```typescript
3704
+ * // Direct usage
3705
+ * const nested = [1, [2, [3, 4]], 5];
3706
+ * const flat1 = Arr.flat(nested, 1); // [1, 2, [3, 4], 5]
3707
+ * const flat2 = Arr.flat(nested, 2); // [1, 2, 3, 4, 5]
3708
+ *
3709
+ * // Curried usage
3710
+ * const flattenOnceLevel = Arr.flat(1);
3711
+ * const result = flattenOnceLevel([[1, 2], [3, 4]]); // [1, 2, 3, 4]
3712
+ *
3713
+ * // Flatten all levels
3714
+ * const deepNested = [1, [2, [3, [4, 5]]]];
3715
+ * const allFlat = Arr.flat(deepNested, SafeUint.MAX_VALUE); // [1, 2, 3, 4, 5]
3716
+ * ```
3717
+ */
3718
+ export function flat<
3719
+ Ar extends readonly unknown[],
3720
+ D extends SafeUintWithSmallInt = 1,
3721
+ >(array: Ar, depth?: D): readonly FlatArray<Ar, D>[];
3722
+
3723
+ export function flat<D extends SafeUintWithSmallInt = 1>(
3724
+ depth?: number,
3725
+ ): <Ar extends readonly unknown[]>(array: Ar) => readonly FlatArray<Ar, D>[];
3726
+
3727
+ export function flat<E, D extends SafeUintWithSmallInt = 1>(
3728
+ ...args: readonly [array: readonly E[], depth?: D] | readonly [depth?: D]
3729
+ ): readonly unknown[] | ((array: readonly unknown[]) => readonly unknown[]) {
3730
+ switch (args.length) {
3731
+ case 2: {
3732
+ const [array, depth] = args;
3733
+ return array.flat(depth);
3734
+ }
3735
+ case 1: {
3736
+ const [arrayOrDepth] = args;
3737
+ if (typeof arrayOrDepth === 'number') {
3738
+ const depth = arrayOrDepth as SafeUintWithSmallInt | undefined;
3739
+ return (array) => flat(array, depth);
3740
+ } else if (arrayOrDepth === undefined) {
3741
+ return (array) => flat(array, 1);
3742
+ } else {
3743
+ expectType<typeof arrayOrDepth, readonly E[]>('=');
3744
+ return arrayOrDepth.flat(1);
3745
+ }
3746
+ }
3747
+
3748
+ case 0:
3749
+ return (array) => flat(array, 1);
3750
+ }
3751
+ }
3752
+
3753
+ /**
3754
+ * Creates a new array with all sub-array elements concatenated into it recursively up to the specified depth,
3755
+ * after first mapping each element using a mapping function.
3756
+ *
3757
+ * This function is equivalent to calling `map` followed by `flat` with depth 1.
3758
+ *
3759
+ * @template Ar The exact type of the input array.
3760
+ * @template E The type of elements in the array.
3761
+ * @template B The type of elements returned by the mapping function.
3762
+ * @param array The array to map and flatten.
3763
+ * @param mapFn A function that produces new elements for the new array.
3764
+ * @returns A new array with mapped elements flattened.
3765
+ *
3766
+ * @example
3767
+ * ```typescript
3768
+ * // Direct usage
3769
+ * const words = ['hello', 'world'];
3770
+ * const chars = Arr.flatMap(words, word => word.split('')); // ['h','e','l','l','o','w','o','r','l','d']
3771
+ *
3772
+ * // Curried usage
3773
+ * const splitWords = Arr.flatMap((word: string) => word.split(''));
3774
+ * const result = splitWords(['foo', 'bar']); // ['f','o','o','b','a','r']
3775
+ *
3776
+ * // With numbers
3777
+ * const numbers = [1, 2, 3];
3778
+ * const doubled = Arr.flatMap(numbers, n => [n, n * 2]); // [1, 2, 2, 4, 3, 6]
3779
+ * ```
3780
+ */
3781
+ export function flatMap<const Ar extends readonly unknown[], B>(
3782
+ array: Ar,
3783
+ mapFn: (a: Ar[number], index: ArrayIndex<Ar>) => readonly B[],
3784
+ ): readonly B[];
3785
+
3786
+ export function flatMap<A, B>(
3787
+ mapFn: (a: A, index: SizeType.Arr) => readonly B[],
3788
+ ): (array: readonly A[]) => readonly B[];
3789
+
3790
+ export function flatMap<A, B>(
3791
+ ...args:
3792
+ | readonly [
3793
+ array: readonly A[],
3794
+ mapFn: (a: A, index: SizeType.Arr) => readonly B[],
3795
+ ]
3796
+ | readonly [mapFn: (a: A, index: SizeType.Arr) => readonly B[]]
3797
+ ): readonly B[] | ((array: readonly A[]) => readonly B[]) {
3798
+ switch (args.length) {
3799
+ case 2: {
3800
+ const [array, mapFn] = args;
3801
+ return array.flatMap((a, i) => mapFn(a, asUint32(i)));
3802
+ }
3803
+ case 1: {
3804
+ const [mapFn] = args;
3805
+ return (array: readonly A[]) => flatMap(array, mapFn);
3065
3806
  }
3066
3807
  }
3067
3808
  }
@@ -3133,11 +3874,46 @@ export namespace Arr {
3133
3874
  }
3134
3875
  case 1: {
3135
3876
  const [chunkSize] = args;
3136
- return (array: readonly E[]) => partition(array, chunkSize);
3877
+ return (array) => partition(array, chunkSize);
3137
3878
  }
3138
3879
  }
3139
3880
  }
3140
3881
 
3882
+ /**
3883
+ * Reverses a tuple, preserving element types in their new positions.
3884
+ *
3885
+ * The type system precisely tracks the reversal, so the returned tuple
3886
+ * has its element types in the exact reverse order. This is more precise
3887
+ * than array reversal which loses positional type information.
3888
+ *
3889
+ * @template T - The tuple type to reverse
3890
+ * @param array - The input tuple
3891
+ * @returns A new tuple with elements in reverse order and precise typing
3892
+ *
3893
+ * @example
3894
+ * ```typescript
3895
+ * // Basic reversal
3896
+ * const nums = [1, 2, 3] as const;
3897
+ * const reversed = Arr.toReversed(nums); // readonly [3, 2, 1]
3898
+ *
3899
+ * // Mixed types preserved in reverse positions
3900
+ * const mixed = [1, 'hello', true, null] as const;
3901
+ * const revMixed = Arr.toReversed(mixed);
3902
+ * // readonly [null, true, 'hello', 1]
3903
+ *
3904
+ * // Empty and single-element tuples
3905
+ * const empty = [] as const;
3906
+ * const revEmpty = Arr.toReversed(empty); // readonly []
3907
+ * const single = [42] as const;
3908
+ * const revSingle = Arr.toReversed(single); // readonly [42]
3909
+ * ```
3910
+ */
3911
+ export const toReversed = <const Ar extends readonly unknown[]>(
3912
+ array: Ar,
3913
+ ): List.Reverse<Ar> =>
3914
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
3915
+ array.toReversed() as never;
3916
+
3141
3917
  /**
3142
3918
  * Sorts an array by a value derived from its elements, using a numeric mapping.
3143
3919
  * @template E The type of elements in the array.
@@ -3154,17 +3930,66 @@ export namespace Arr {
3154
3930
  * // [{ name: 'Adam', score: 90 }, { name: 'Bob', score: 80 }, { name: 'Eve', score: 70 }]
3155
3931
  * ```
3156
3932
  */
3157
- export function toSortedBy<E>(
3158
- array: readonly E[],
3159
- comparatorValueMapper: (value: E) => number,
3933
+ export const toSorted = <Ar extends readonly unknown[]>(
3934
+ ...[array, comparator]: Ar extends readonly number[]
3935
+ ? readonly [
3936
+ array: Ar,
3937
+ // If the array elements are mapped to numbers, comparator is optional.
3938
+ comparator?: (x: Ar[number], y: Ar[number]) => number,
3939
+ ]
3940
+ : readonly [
3941
+ array: Ar,
3942
+ comparator: (x: Ar[number], y: Ar[number]) => number,
3943
+ ]
3944
+ ): IsFixedLengthList<Ar> extends true
3945
+ ? ArrayOfLength<Ar['length'], Ar[number]>
3946
+ : Ar extends NonEmptyArray<unknown>
3947
+ ? NonEmptyArray<Ar[number]>
3948
+ : readonly Ar[number][] =>
3949
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
3950
+ array.toSorted(
3951
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
3952
+ (comparator as ((x: unknown, y: unknown) => number) | undefined) ??
3953
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
3954
+ ((x, y) => (x as number) - (y as number)),
3955
+ ) as never;
3956
+
3957
+ /**
3958
+ * Sorts an array by a value derived from its elements, using a numeric mapping.
3959
+ * @template E The type of elements in the array.
3960
+ * @param array The input array.
3961
+ * @param comparatorValueMapper A function `(value: A) => number` that maps an element to a number for comparison.
3962
+ * @param comparator An optional custom comparator function `(x: number, y: number) => number` for the mapped numbers. Defaults to ascending sort (x - y).
3963
+ * @returns A new array sorted by the mapped values.
3964
+ * @example
3965
+ * ```ts
3966
+ * const items = [{ name: 'Eve', score: 70 }, { name: 'Adam', score: 90 }, { name: 'Bob', score: 80 }];
3967
+ * Arr.toSortedBy(items, item => item.score);
3968
+ * // [{ name: 'Eve', score: 70 }, { name: 'Bob', score: 80 }, { name: 'Adam', score: 90 }]
3969
+ * Arr.toSortedBy(items, item => item.score, (a, b) => b - a); // Sort descending
3970
+ * // [{ name: 'Adam', score: 90 }, { name: 'Bob', score: 80 }, { name: 'Eve', score: 70 }]
3971
+ * ```
3972
+ */
3973
+ export function toSortedBy<Ar extends readonly unknown[]>(
3974
+ array: Ar,
3975
+ comparatorValueMapper: (value: Ar[number]) => number,
3976
+ // If the array elements are mapped to numbers, comparator is optional.
3160
3977
  comparator?: (x: number, y: number) => number,
3161
- ): readonly E[];
3978
+ ): IsFixedLengthList<Ar> extends true
3979
+ ? ArrayOfLength<Ar['length'], Ar[number]>
3980
+ : Ar extends NonEmptyArray<unknown>
3981
+ ? NonEmptyArray<Ar[number]>
3982
+ : readonly Ar[number][];
3162
3983
 
3163
- export function toSortedBy<E, const V>(
3164
- array: readonly E[],
3165
- comparatorValueMapper: (value: E) => V,
3984
+ export function toSortedBy<Ar extends readonly unknown[], const V>(
3985
+ array: Ar,
3986
+ comparatorValueMapper: (value: Ar[number]) => V,
3166
3987
  comparator: (x: V, y: V) => number,
3167
- ): readonly E[];
3988
+ ): IsFixedLengthList<Ar> extends true
3989
+ ? ArrayOfLength<Ar['length'], Ar[number]>
3990
+ : Ar extends NonEmptyArray<unknown>
3991
+ ? NonEmptyArray<Ar[number]>
3992
+ : readonly Ar[number][];
3168
3993
 
3169
3994
  export function toSortedBy<E, const V>(
3170
3995
  array: readonly E[],
@@ -3240,8 +4065,8 @@ export namespace Arr {
3240
4065
  *
3241
4066
  * // Running maximum
3242
4067
  * const temperatures = [20, 25, 18, 30, 22];
3243
- * const runningMax = Arr.scan(temperatures, (max, temp) => Math.max(max, temp), -Infinity);
3244
- * // [-Infinity, 20, 25, 25, 30, 30]
4068
+ * const runningMax = Arr.scan(temperatures, (max, temp) => Math.max(max, temp), Number.NEGATIVE_INFINITY);
4069
+ * // [Number.NEGATIVE_INFINITY, 20, 25, 25, 30, 30]
3245
4070
  *
3246
4071
  * // Building strings incrementally
3247
4072
  * const words = ['Hello', 'beautiful', 'world'];
@@ -3339,9 +4164,13 @@ export namespace Arr {
3339
4164
  * @see {@link SizeType.Arr} for the index parameter type
3340
4165
  * @see Array.prototype.reduce for the standard reduce function
3341
4166
  */
3342
- export function scan<E, S>(
3343
- array: readonly E[],
3344
- reducer: (accumulator: S, currentValue: E, currentIndex: SizeType.Arr) => S,
4167
+ export function scan<Ar extends readonly unknown[], S>(
4168
+ array: Ar,
4169
+ reducer: (
4170
+ accumulator: S,
4171
+ currentValue: Ar[number],
4172
+ currentIndex: ArrayIndex<Ar>,
4173
+ ) => S,
3345
4174
  init: S,
3346
4175
  ): NonEmptyArray<S>;
3347
4176
 
@@ -3374,7 +4203,7 @@ export namespace Arr {
3374
4203
  case 3: {
3375
4204
  const [array, reducer, init] = args;
3376
4205
  const mut_result: MutableNonEmptyArray<S> = castMutable(
3377
- newArray<S>(asPositiveUint32(array.length + 1), init),
4206
+ newArray<S, PositiveUint32>(asPositiveUint32(array.length + 1), init),
3378
4207
  );
3379
4208
 
3380
4209
  let mut_acc = init;
@@ -3388,7 +4217,7 @@ export namespace Arr {
3388
4217
  }
3389
4218
  case 2: {
3390
4219
  const [reducer, init] = args;
3391
- return (array: readonly E[]) => scan(array, reducer, init);
4220
+ return (array) => scan(array, reducer, init);
3392
4221
  }
3393
4222
  }
3394
4223
  }
@@ -3542,10 +4371,13 @@ export namespace Arr {
3542
4371
  * @see {@link IMap.map} for transforming grouped data
3543
4372
  * @see {@link Optional} for handling potentially missing groups
3544
4373
  */
3545
- export function groupBy<E, G extends MapSetKeyType>(
3546
- array: readonly E[],
3547
- grouper: (value: E, index: SizeType.Arr) => G,
3548
- ): IMap<G, readonly E[]>;
4374
+ export function groupBy<
4375
+ Ar extends readonly unknown[],
4376
+ G extends MapSetKeyType,
4377
+ >(
4378
+ array: Ar,
4379
+ grouper: (value: Ar[number], index: ArrayIndex<Ar>) => G,
4380
+ ): IMap<G, readonly Ar[number][]>;
3549
4381
 
3550
4382
  export function groupBy<E, G extends MapSetKeyType>(
3551
4383
  grouper: (value: E, index: SizeType.Arr) => G,
@@ -3578,7 +4410,7 @@ export namespace Arr {
3578
4410
  }
3579
4411
  case 1: {
3580
4412
  const [grouper] = args;
3581
- return (array: readonly E[]) => groupBy(array, grouper);
4413
+ return (array) => groupBy(array, grouper);
3582
4414
  }
3583
4415
  }
3584
4416
  }
@@ -3594,9 +4426,13 @@ export namespace Arr {
3594
4426
  * Arr.uniq([1, 2, 2, 3, 1, 4]); // [1, 2, 3, 4]
3595
4427
  * ```
3596
4428
  */
3597
- export const uniq = <P extends Primitive>(
3598
- array: readonly P[],
3599
- ): readonly P[] => Array.from(new Set(array));
4429
+ export const uniq = <Ar extends readonly Primitive[]>(
4430
+ array: Ar,
4431
+ ): Ar extends NonEmptyArray<unknown>
4432
+ ? NonEmptyArray<Ar[number]>
4433
+ : readonly Ar[number][] =>
4434
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
4435
+ Array.from(new Set(array)) as never;
3600
4436
 
3601
4437
  /**
3602
4438
  * Creates a new array with unique elements from the input array, based on the values returned by `mapFn`.
@@ -3619,22 +4455,15 @@ export namespace Arr {
3619
4455
  * Arr.uniqBy(users, user => user.id); // [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]
3620
4456
  * ```
3621
4457
  */
3622
- export function uniqBy<E, P extends Primitive>(
3623
- array: NonEmptyArray<E>,
3624
- mapFn: (value: E) => P,
3625
- ): NonEmptyArray<E>;
3626
-
3627
- export function uniqBy<E, P extends Primitive>(
3628
- array: readonly E[],
3629
- mapFn: (value: E) => P,
3630
- ): readonly E[];
3631
-
3632
- export function uniqBy<E, P extends Primitive>(
3633
- array: readonly E[],
3634
- mapFn: (value: E) => P,
3635
- ): readonly E[] {
4458
+ export const uniqBy = <Ar extends readonly unknown[], P extends Primitive>(
4459
+ array: Ar,
4460
+ mapFn: (value: Ar[number]) => P,
4461
+ ): Ar extends NonEmptyArray<unknown>
4462
+ ? NonEmptyArray<Ar[number]>
4463
+ : readonly Ar[number][] => {
3636
4464
  const mut_mappedValues = new Set<P>();
3637
4465
 
4466
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
3638
4467
  return array.filter((val) => {
3639
4468
  const mappedValue = mapFn(val);
3640
4469
 
@@ -3642,8 +4471,8 @@ export namespace Arr {
3642
4471
  mut_mappedValues.add(mappedValue);
3643
4472
 
3644
4473
  return true;
3645
- });
3646
- }
4474
+ }) satisfies readonly Ar[number][] as never;
4475
+ };
3647
4476
 
3648
4477
  // set operations & equality
3649
4478
 
@@ -3821,6 +4650,100 @@ export namespace Arr {
3821
4650
  return mut_result;
3822
4651
  };
3823
4652
 
4653
+ // iterators
4654
+
4655
+ /**
4656
+ * Returns an iterable of key-value pairs for every entry in the array.
4657
+ *
4658
+ * This function returns an array where each element is a tuple containing the index and value.
4659
+ * The indices are branded as `SizeType.Arr` for type safety.
4660
+ *
4661
+ * @template Ar The exact type of the input array.
4662
+ * @param array The array to get entries from.
4663
+ * @returns An array of `[index, value]` pairs.
4664
+ *
4665
+ * @example
4666
+ * ```typescript
4667
+ * // Direct usage
4668
+ * const fruits = ['apple', 'banana', 'cherry'];
4669
+ * const entries = Arr.entries(fruits); // [[0, 'apple'], [1, 'banana'], [2, 'cherry']]
4670
+ *
4671
+ * // Curried usage
4672
+ * const getEntries = Arr.entries;
4673
+ * const result = getEntries(['a', 'b']); // [[0, 'a'], [1, 'b']]
4674
+ *
4675
+ * // With tuples
4676
+ * const tuple = [10, 20, 30] as const;
4677
+ * const tupleEntries = Arr.entries(tuple); // [[0, 10], [1, 20], [2, 30]]
4678
+ * ```
4679
+ */
4680
+ export function* entries<E>(
4681
+ array: readonly E[],
4682
+ ): ArrayIterator<readonly [SizeType.Arr, E]> {
4683
+ for (const [index, value] of array.entries()) {
4684
+ yield [asUint32(index), value] as const;
4685
+ }
4686
+ }
4687
+
4688
+ /**
4689
+ * Returns an iterable of values in the array.
4690
+ *
4691
+ * This function is essentially an identity function that returns a copy of the array.
4692
+ * It's included for API completeness and consistency with native Array methods.
4693
+ *
4694
+ * @template Ar The exact type of the input array.
4695
+ * @param array The array to get values from.
4696
+ * @returns A copy of the input array.
4697
+ *
4698
+ * @example
4699
+ * ```typescript
4700
+ * // Direct usage
4701
+ * const numbers = [1, 2, 3];
4702
+ * const values = Arr.values(numbers); // [1, 2, 3]
4703
+ *
4704
+ * // Curried usage
4705
+ * const getValues = Arr.values;
4706
+ * const result = getValues(['a', 'b']); // ['a', 'b']
4707
+ * ```
4708
+ */
4709
+ export function* values<E>(array: readonly E[]): ArrayIterator<E> {
4710
+ for (const value of array.values()) {
4711
+ yield value;
4712
+ }
4713
+ }
4714
+
4715
+ /**
4716
+ * Returns an iterable of keys in the array.
4717
+ *
4718
+ * This function returns an array of branded indices (`SizeType.Arr`) for type safety.
4719
+ *
4720
+ * @template Ar The exact type of the input array.
4721
+ * @param array The array to get indices from.
4722
+ * @returns An array of indices.
4723
+ *
4724
+ * @example
4725
+ * ```typescript
4726
+ * // Direct usage
4727
+ * const fruits = ['apple', 'banana', 'cherry'];
4728
+ * const indices = Arr.indices(fruits); // [0, 1, 2]
4729
+ *
4730
+ * // Curried usage
4731
+ * const getIndices = Arr.indices;
4732
+ * const result = getIndices(['a', 'b']); // [0, 1]
4733
+ *
4734
+ * // Empty array
4735
+ * const empty: string[] = [];
4736
+ * const emptyIndices = Arr.indices(empty); // []
4737
+ * ```
4738
+ */
4739
+ export function* indices<E>(
4740
+ array: readonly E[],
4741
+ ): ArrayIterator<SizeType.Arr> {
4742
+ for (const key of array.keys()) {
4743
+ yield asUint32(key);
4744
+ }
4745
+ }
4746
+
3824
4747
  // aliases
3825
4748
 
3826
4749
  /**
@@ -3858,4 +4781,22 @@ export namespace Arr {
3858
4781
  * @see {@link partition}
3859
4782
  */
3860
4783
  export const chunk = partition;
4784
+
4785
+ /**
4786
+ * Alias for `create`. Creates a new array of the specified length, with each position filled with the provided initial value.
4787
+ * @see {@link create}
4788
+ */
4789
+ export const newArray = create;
4790
+
4791
+ /**
4792
+ * Alias for `size`. Returns the length of an array.
4793
+ * @see {@link size}
4794
+ */
4795
+ export const length = size;
4796
+
4797
+ /**
4798
+ * Alias for `indices`. Returns an iterable of keys in the array.
4799
+ * @see {@link indices}
4800
+ */
4801
+ export const keys = indices;
3861
4802
  }