ts-data-forge 14.10.0 → 14.10.2

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 (103) hide show
  1. package/README.md +5 -5
  2. package/dist/array/impl/array-utils-element-access.d.mts.map +1 -1
  3. package/dist/array/impl/array-utils-element-access.mjs +4 -4
  4. package/dist/array/impl/array-utils-element-access.mjs.map +1 -1
  5. package/dist/array/impl/array-utils-length-bounded-array-cast.d.mts +8 -8
  6. package/dist/array/impl/array-utils-length-bounded-array-cast.d.mts.map +1 -1
  7. package/dist/array/impl/array-utils-length-bounded-array-cast.mjs +28 -28
  8. package/dist/array/impl/array-utils-length-bounded-array-cast.mjs.map +1 -1
  9. package/dist/array/impl/array-utils-length-bounded-array-guard.d.mts.map +1 -1
  10. package/dist/array/impl/array-utils-length-bounded-array-guard.mjs +4 -4
  11. package/dist/array/impl/array-utils-length-bounded-array-guard.mjs.map +1 -1
  12. package/dist/array/impl/array-utils-length-bounded-tuple-cast.d.mts +3 -4
  13. package/dist/array/impl/array-utils-length-bounded-tuple-cast.d.mts.map +1 -1
  14. package/dist/array/impl/array-utils-length-bounded-tuple-cast.mjs +28 -29
  15. package/dist/array/impl/array-utils-length-bounded-tuple-cast.mjs.map +1 -1
  16. package/dist/array/impl/array-utils-length-bounded-tuple-guard.d.mts.map +1 -1
  17. package/dist/array/impl/array-utils-length-bounded-tuple-guard.mjs +3 -3
  18. package/dist/array/impl/array-utils-length-bounded-tuple-guard.mjs.map +1 -1
  19. package/dist/array/impl/array-utils-modification.d.mts +1 -1
  20. package/dist/array/impl/array-utils-modification.d.mts.map +1 -1
  21. package/dist/array/impl/array-utils-modification.mjs +15 -15
  22. package/dist/array/impl/array-utils-modification.mjs.map +1 -1
  23. package/dist/array/impl/array-utils-reducing-value.d.mts.map +1 -1
  24. package/dist/array/impl/array-utils-reducing-value.mjs +12 -12
  25. package/dist/array/impl/array-utils-reducing-value.mjs.map +1 -1
  26. package/dist/array/impl/array-utils-search.d.mts.map +1 -1
  27. package/dist/array/impl/array-utils-search.mjs +56 -56
  28. package/dist/array/impl/array-utils-search.mjs.map +1 -1
  29. package/dist/array/impl/array-utils-slicing.d.mts.map +1 -1
  30. package/dist/array/impl/array-utils-slicing.mjs +3 -3
  31. package/dist/array/impl/array-utils-slicing.mjs.map +1 -1
  32. package/dist/array/impl/array-utils-transformation.d.mts +25 -25
  33. package/dist/array/impl/array-utils-transformation.d.mts.map +1 -1
  34. package/dist/array/impl/array-utils-transformation.mjs +22 -22
  35. package/dist/array/impl/array-utils-transformation.mjs.map +1 -1
  36. package/dist/array/impl/array-utils-validation.d.mts.map +1 -1
  37. package/dist/array/impl/array-utils-validation.mjs +2 -2
  38. package/dist/array/impl/array-utils-validation.mjs.map +1 -1
  39. package/dist/collections/imap-mapped.d.mts +2 -2
  40. package/dist/collections/imap-mapped.mjs +6 -3
  41. package/dist/collections/imap-mapped.mjs.map +1 -1
  42. package/dist/collections/imap.d.mts +3 -4
  43. package/dist/collections/imap.d.mts.map +1 -1
  44. package/dist/collections/imap.mjs +6 -4
  45. package/dist/collections/imap.mjs.map +1 -1
  46. package/dist/collections/iset-mapped.d.mts +1 -2
  47. package/dist/collections/iset-mapped.d.mts.map +1 -1
  48. package/dist/collections/iset-mapped.mjs.map +1 -1
  49. package/dist/collections/iset.d.mts +4 -5
  50. package/dist/collections/iset.d.mts.map +1 -1
  51. package/dist/collections/iset.mjs +0 -1
  52. package/dist/collections/iset.mjs.map +1 -1
  53. package/dist/json/json.d.mts.map +1 -1
  54. package/dist/json/json.mjs +13 -47
  55. package/dist/json/json.mjs.map +1 -1
  56. package/dist/number/num.d.mts +12 -8
  57. package/dist/number/num.d.mts.map +1 -1
  58. package/dist/number/num.mjs +5 -1
  59. package/dist/number/num.mjs.map +1 -1
  60. package/dist/object/object.d.mts +10 -2
  61. package/dist/object/object.d.mts.map +1 -1
  62. package/dist/object/object.mjs +16 -4
  63. package/dist/object/object.mjs.map +1 -1
  64. package/dist/others/fast-deep-equal.d.mts.map +1 -1
  65. package/dist/others/fast-deep-equal.mjs +10 -7
  66. package/dist/others/fast-deep-equal.mjs.map +1 -1
  67. package/dist/others/replace-equal-deep.d.mts +9 -9
  68. package/dist/others/replace-equal-deep.mjs +22 -15
  69. package/dist/others/replace-equal-deep.mjs.map +1 -1
  70. package/dist/string/str.d.mts +2 -2
  71. package/package.json +12 -12
  72. package/src/array/impl/array-utils-element-access.mts +11 -11
  73. package/src/array/impl/array-utils-length-bounded-array-cast.mts +69 -69
  74. package/src/array/impl/array-utils-length-bounded-array-guard.mts +21 -21
  75. package/src/array/impl/array-utils-length-bounded-array-guard.test.mts +2 -2
  76. package/src/array/impl/array-utils-length-bounded-tuple-cast.mts +64 -65
  77. package/src/array/impl/array-utils-length-bounded-tuple-guard.mts +15 -15
  78. package/src/array/impl/array-utils-modification.mts +54 -54
  79. package/src/array/impl/array-utils-reducing-value.mts +55 -55
  80. package/src/array/impl/array-utils-search.mts +114 -114
  81. package/src/array/impl/array-utils-slicing.mts +16 -16
  82. package/src/array/impl/array-utils-transformation.mts +96 -96
  83. package/src/array/impl/array-utils-transformation.test.mts +54 -5
  84. package/src/array/impl/array-utils-validation.mts +19 -19
  85. package/src/array/impl/array-utils-validation.test.mts +1 -1
  86. package/src/collections/imap-mapped.mts +8 -6
  87. package/src/collections/imap-mapped.test.mts +27 -0
  88. package/src/collections/imap.mts +9 -8
  89. package/src/collections/imap.test.mts +14 -1
  90. package/src/collections/iset-mapped.mts +1 -2
  91. package/src/collections/iset.mts +4 -5
  92. package/src/collections/iset.test.mts +1 -1
  93. package/src/json/json.mts +17 -57
  94. package/src/json/json.test.mts +32 -0
  95. package/src/number/num.mts +21 -17
  96. package/src/number/num.test.mts +13 -1
  97. package/src/object/object.mts +34 -6
  98. package/src/object/object.test.mts +55 -0
  99. package/src/others/fast-deep-equal.mts +17 -10
  100. package/src/others/fast-deep-equal.test.mts +141 -29
  101. package/src/others/replace-equal-deep.mts +48 -41
  102. package/src/others/replace-equal-deep.test.mts +39 -7
  103. package/src/string/str.mts +2 -2
@@ -18,8 +18,8 @@ import {
18
18
  * exactly `length` elements.
19
19
  *
20
20
  * Use this instead of writing `xs as unknown as FixedLengthArray<N, E>`: the
21
- * length is verified at runtime, and the original array type (e.g. tuple
22
- * types) is preserved via intersection, so the result also benefits from the
21
+ * length is verified at runtime, and the original array type (e.g. tuple types)
22
+ * is preserved via intersection, so the result also benefits from the
23
23
  * structural tuple prefix (in-range indexed access without `undefined` under
24
24
  * `noUncheckedIndexedAccess`).
25
25
  *
@@ -83,28 +83,13 @@ export function asFixedLengthArray<E>(
83
83
  }
84
84
  }
85
85
 
86
- const asFixedLengthArrayImpl = <E,>(
87
- length: SupportedLength,
88
- xs: readonly E[],
89
- ): readonly E[] => {
90
- const actualLength = xs.length;
91
-
92
- if (!isFixedLengthArray(length, xs)) {
93
- throw new TypeError(
94
- `Expected an array of length ${length}, got an array of length ${actualLength}`,
95
- );
96
- }
97
-
98
- return xs;
99
- };
100
-
101
86
  /**
102
87
  * Casts an array to `MinLengthArray<MinLength, E>` after checking that it has
103
88
  * at least `minLength` elements.
104
89
  *
105
90
  * Use this instead of writing `xs as unknown as MinLengthArray<N, E>`: the
106
- * length is verified at runtime, and the original array type (e.g. tuple
107
- * types) is preserved via intersection, so the result also benefits from the
91
+ * length is verified at runtime, and the original array type (e.g. tuple types)
92
+ * is preserved via intersection, so the result also benefits from the
108
93
  * structural tuple prefix (indexed access below `min(N, 10)` without
109
94
  * `undefined` under `noUncheckedIndexedAccess`).
110
95
  *
@@ -168,28 +153,13 @@ export function asMinLengthArray<E>(
168
153
  }
169
154
  }
170
155
 
171
- const asMinLengthArrayImpl = <E,>(
172
- minLength: SupportedLength,
173
- xs: readonly E[],
174
- ): readonly E[] => {
175
- const actualLength = xs.length;
176
-
177
- if (!isMinLengthArray(minLength, xs)) {
178
- throw new TypeError(
179
- `Expected an array of length >= ${minLength}, got an array of length ${actualLength}`,
180
- );
181
- }
182
-
183
- return xs;
184
- };
185
-
186
156
  /**
187
157
  * Casts an array to `MaxLengthArray<MaxLength, E>` after checking that it has
188
158
  * at most `maxLength` elements.
189
159
  *
190
160
  * Use this instead of writing `xs as unknown as MaxLengthArray<N, E>`: the
191
- * length is verified at runtime, and the original array type (e.g. tuple
192
- * types) is preserved via intersection.
161
+ * length is verified at runtime, and the original array type (e.g. tuple types)
162
+ * is preserved via intersection.
193
163
  *
194
164
  * The length argument comes first, matching the type-parameter order of
195
165
  * `MaxLengthArray<MaxLength, Elm>`. Omitting the array returns a function that
@@ -247,29 +217,14 @@ export function asMaxLengthArray<E>(
247
217
  }
248
218
  }
249
219
 
250
- const asMaxLengthArrayImpl = <E,>(
251
- maxLength: SupportedLength,
252
- xs: readonly E[],
253
- ): readonly E[] => {
254
- const actualLength = xs.length;
255
-
256
- if (!isMaxLengthArray(maxLength, xs)) {
257
- throw new TypeError(
258
- `Expected an array of length <= ${maxLength}, got an array of length ${actualLength}`,
259
- );
260
- }
261
-
262
- return xs;
263
- };
264
-
265
220
  /**
266
221
  * Casts an array to `BoundedLengthArray<MinLength, MaxLength, E>` after
267
222
  * checking that its length is within the inclusive range
268
223
  * `[minLength, maxLength]`.
269
224
  *
270
225
  * Use this instead of writing
271
- * `xs as unknown as BoundedLengthArray<Min, Max, E>`: the length is verified
272
- * at runtime, and the original array type (e.g. tuple types) is preserved via
226
+ * `xs as unknown as BoundedLengthArray<Min, Max, E>`: the length is verified at
227
+ * runtime, and the original array type (e.g. tuple types) is preserved via
273
228
  * intersection.
274
229
  *
275
230
  * The length arguments come first, matching the type-parameter order of
@@ -344,22 +299,6 @@ export function asBoundedLengthArray<E>(
344
299
  }
345
300
  }
346
301
 
347
- const asBoundedLengthArrayImpl = <E,>(
348
- minLength: SupportedLength,
349
- maxLength: SupportedLength,
350
- xs: readonly E[],
351
- ): readonly E[] => {
352
- const actualLength = xs.length;
353
-
354
- if (!isBoundedLengthArray(minLength, maxLength, xs)) {
355
- throw new TypeError(
356
- `Expected an array of length in [${minLength}, ${maxLength}], got an array of length ${actualLength}`,
357
- );
358
- }
359
-
360
- return xs;
361
- };
362
-
363
302
  /**
364
303
  * Casts an array to `FixedLengthArray<0, E>` after checking that it is empty.
365
304
  *
@@ -434,3 +373,64 @@ export const asNonEmptyArray = <Xs extends readonly unknown[]>(
434
373
 
435
374
  return xs;
436
375
  };
376
+
377
+ const asFixedLengthArrayImpl = <E,>(
378
+ length: SupportedLength,
379
+ xs: readonly E[],
380
+ ): readonly E[] => {
381
+ const actualLength = xs.length;
382
+
383
+ if (!isFixedLengthArray(length, xs)) {
384
+ throw new TypeError(
385
+ `Expected an array of length ${length}, got an array of length ${actualLength}`,
386
+ );
387
+ }
388
+
389
+ return xs;
390
+ };
391
+
392
+ const asMinLengthArrayImpl = <E,>(
393
+ minLength: SupportedLength,
394
+ xs: readonly E[],
395
+ ): readonly E[] => {
396
+ const actualLength = xs.length;
397
+
398
+ if (!isMinLengthArray(minLength, xs)) {
399
+ throw new TypeError(
400
+ `Expected an array of length >= ${minLength}, got an array of length ${actualLength}`,
401
+ );
402
+ }
403
+
404
+ return xs;
405
+ };
406
+
407
+ const asMaxLengthArrayImpl = <E,>(
408
+ maxLength: SupportedLength,
409
+ xs: readonly E[],
410
+ ): readonly E[] => {
411
+ const actualLength = xs.length;
412
+
413
+ if (!isMaxLengthArray(maxLength, xs)) {
414
+ throw new TypeError(
415
+ `Expected an array of length <= ${maxLength}, got an array of length ${actualLength}`,
416
+ );
417
+ }
418
+
419
+ return xs;
420
+ };
421
+
422
+ const asBoundedLengthArrayImpl = <E,>(
423
+ minLength: SupportedLength,
424
+ maxLength: SupportedLength,
425
+ xs: readonly E[],
426
+ ): readonly E[] => {
427
+ const actualLength = xs.length;
428
+
429
+ if (!isBoundedLengthArray(minLength, maxLength, xs)) {
430
+ throw new TypeError(
431
+ `Expected an array of length in [${minLength}, ${maxLength}], got an array of length ${actualLength}`,
432
+ );
433
+ }
434
+
435
+ return xs;
436
+ };
@@ -85,11 +85,6 @@ export function isMinLengthArray(
85
85
  }
86
86
  }
87
87
 
88
- const hasMinLength = (
89
- minLength: SupportedLength,
90
- xs: readonly unknown[],
91
- ): boolean => xs.length >= minLength;
92
-
93
88
  /**
94
89
  * Type guard that checks if an array has at most `maxLength` elements.
95
90
  *
@@ -169,11 +164,6 @@ export function isMaxLengthArray(
169
164
  }
170
165
  }
171
166
 
172
- const hasMaxLength = (
173
- maxLength: SupportedLength,
174
- xs: readonly unknown[],
175
- ): boolean => xs.length <= maxLength;
176
-
177
167
  /**
178
168
  * Type guard that checks if an array's length is within the inclusive range
179
169
  * `[minLength, maxLength]`.
@@ -267,12 +257,6 @@ export function isBoundedLengthArray(
267
257
  }
268
258
  }
269
259
 
270
- const hasBoundedLength = (
271
- minLength: SupportedLength,
272
- maxLength: SupportedLength,
273
- xs: readonly unknown[],
274
- ): boolean => minLength <= xs.length && xs.length <= maxLength;
275
-
276
260
  /**
277
261
  * Type guard that checks if an array has exactly `length` elements.
278
262
  *
@@ -350,11 +334,6 @@ export function isFixedLengthArray(
350
334
  }
351
335
  }
352
336
 
353
- const hasFixedLength = (
354
- length: SupportedLength,
355
- xs: readonly unknown[],
356
- ): boolean => xs.length === length;
357
-
358
337
  /**
359
338
  * Type guard that checks if an array is empty.
360
339
  *
@@ -402,3 +381,24 @@ export const isEmpty = <Xs extends readonly unknown[]>(
402
381
  export const isNonEmpty = <Xs extends readonly unknown[]>(
403
382
  array: Xs,
404
383
  ): array is MinLengthArray<1, Xs[number]> & Xs => array.length > 0;
384
+
385
+ const hasMinLength = (
386
+ minLength: SupportedLength,
387
+ xs: readonly unknown[],
388
+ ): boolean => xs.length >= minLength;
389
+
390
+ const hasMaxLength = (
391
+ maxLength: SupportedLength,
392
+ xs: readonly unknown[],
393
+ ): boolean => xs.length <= maxLength;
394
+
395
+ const hasBoundedLength = (
396
+ minLength: SupportedLength,
397
+ maxLength: SupportedLength,
398
+ xs: readonly unknown[],
399
+ ): boolean => minLength <= xs.length && xs.length <= maxLength;
400
+
401
+ const hasFixedLength = (
402
+ length: SupportedLength,
403
+ xs: readonly unknown[],
404
+ ): boolean => xs.length === length;
@@ -166,8 +166,8 @@ describe(isFixedLengthArray, () => {
166
166
 
167
167
  expectType<typeof value, FixedLengthArray<4, number>>('!<=');
168
168
 
169
- // `length` is narrowed to the literal and in-range indexed access does
170
- // not include `undefined` (even under `noUncheckedIndexedAccess`)
169
+ // `length` is narrowed to the literal and in-range indexed access does not
170
+ // include `undefined` (even under `noUncheckedIndexedAccess`)
171
171
  const _len = value.length;
172
172
 
173
173
  expectType<typeof _len, 3>('=');
@@ -18,8 +18,8 @@ import {
18
18
  * exactly `length` elements.
19
19
  *
20
20
  * This is the structural counterpart of `asFixedLengthArray`: it produces a
21
- * tuple type rather than the branded `FixedLengthArray`. Prefer the branded
22
- * one unless you specifically need the structural type — the brand keeps
21
+ * tuple type rather than the branded `FixedLengthArray`. Prefer the branded one
22
+ * unless you specifically need the structural type — the brand keeps
23
23
  * type-checking cost independent of the element type and of the bound.
24
24
  *
25
25
  * The length argument comes first, matching the type-parameter order of
@@ -76,21 +76,6 @@ export function asFixedLengthTuple(
76
76
  }
77
77
  }
78
78
 
79
- const asFixedLengthTupleImpl = (
80
- length: SizeType.ArgArr,
81
- xs: readonly unknown[],
82
- ): readonly unknown[] => {
83
- const actualLength = xs.length;
84
-
85
- if (!isFixedLengthTuple(length, xs)) {
86
- throw new TypeError(
87
- `Expected an array of length ${length}, got an array of length ${actualLength}`,
88
- );
89
- }
90
-
91
- return xs;
92
- };
93
-
94
79
  /**
95
80
  * Casts an array to `MinLengthTuple<MinLength, E>` after checking that it has
96
81
  * at least `minLength` elements.
@@ -148,21 +133,6 @@ export function asMinLengthTuple(
148
133
  }
149
134
  }
150
135
 
151
- const asMinLengthTupleImpl = (
152
- minLength: SizeType.ArgArr,
153
- xs: readonly unknown[],
154
- ): readonly unknown[] => {
155
- const actualLength = xs.length;
156
-
157
- if (!isMinLengthTuple(minLength, xs)) {
158
- throw new TypeError(
159
- `Expected an array of length >= ${minLength}, got an array of length ${actualLength}`,
160
- );
161
- }
162
-
163
- return xs;
164
- };
165
-
166
136
  /**
167
137
  * Casts an array to `MaxLengthTuple<MaxLength, E>` after checking that it has
168
138
  * at most `maxLength` elements.
@@ -218,21 +188,6 @@ export function asMaxLengthTuple(
218
188
  }
219
189
  }
220
190
 
221
- const asMaxLengthTupleImpl = (
222
- maxLength: SizeType.ArgArr,
223
- xs: readonly unknown[],
224
- ): readonly unknown[] => {
225
- const actualLength = xs.length;
226
-
227
- if (!isMaxLengthTuple(maxLength, xs)) {
228
- throw new TypeError(
229
- `Expected an array of length <= ${maxLength}, got an array of length ${actualLength}`,
230
- );
231
- }
232
-
233
- return xs;
234
- };
235
-
236
191
  /**
237
192
  * Casts an array to `BoundedLengthTuple<Min, Max, E>` after checking that its
238
193
  * length is within the inclusive range `[min, max]`.
@@ -299,25 +254,8 @@ export function asBoundedLengthTuple(
299
254
  }
300
255
  }
301
256
 
302
- const asBoundedLengthTupleImpl = (
303
- min: SizeType.ArgArr,
304
- max: SizeType.ArgArr,
305
- xs: readonly unknown[],
306
- ): readonly unknown[] => {
307
- const actualLength = xs.length;
308
-
309
- if (!isBoundedLengthTuple(min, max, xs)) {
310
- throw new TypeError(
311
- `Expected an array of length in [${min}, ${max}], got an array of length ${actualLength}`,
312
- );
313
- }
314
-
315
- return xs;
316
- };
317
-
318
257
  /**
319
- * Casts an array to the structural empty tuple after checking that it is
320
- * empty.
258
+ * Casts an array to the structural empty tuple after checking that it is empty.
321
259
  *
322
260
  * This is the structural counterpart of `asEmptyArray`, and the length-0
323
261
  * specialization of {@link asFixedLengthTuple}.
@@ -382,3 +320,64 @@ export const asNonEmptyTuple = <Xs extends readonly unknown[]>(
382
320
 
383
321
  return xs;
384
322
  };
323
+
324
+ const asFixedLengthTupleImpl = (
325
+ length: SizeType.ArgArr,
326
+ xs: readonly unknown[],
327
+ ): readonly unknown[] => {
328
+ const actualLength = xs.length;
329
+
330
+ if (!isFixedLengthTuple(length, xs)) {
331
+ throw new TypeError(
332
+ `Expected an array of length ${length}, got an array of length ${actualLength}`,
333
+ );
334
+ }
335
+
336
+ return xs;
337
+ };
338
+
339
+ const asMinLengthTupleImpl = (
340
+ minLength: SizeType.ArgArr,
341
+ xs: readonly unknown[],
342
+ ): readonly unknown[] => {
343
+ const actualLength = xs.length;
344
+
345
+ if (!isMinLengthTuple(minLength, xs)) {
346
+ throw new TypeError(
347
+ `Expected an array of length >= ${minLength}, got an array of length ${actualLength}`,
348
+ );
349
+ }
350
+
351
+ return xs;
352
+ };
353
+
354
+ const asMaxLengthTupleImpl = (
355
+ maxLength: SizeType.ArgArr,
356
+ xs: readonly unknown[],
357
+ ): readonly unknown[] => {
358
+ const actualLength = xs.length;
359
+
360
+ if (!isMaxLengthTuple(maxLength, xs)) {
361
+ throw new TypeError(
362
+ `Expected an array of length <= ${maxLength}, got an array of length ${actualLength}`,
363
+ );
364
+ }
365
+
366
+ return xs;
367
+ };
368
+
369
+ const asBoundedLengthTupleImpl = (
370
+ min: SizeType.ArgArr,
371
+ max: SizeType.ArgArr,
372
+ xs: readonly unknown[],
373
+ ): readonly unknown[] => {
374
+ const actualLength = xs.length;
375
+
376
+ if (!isBoundedLengthTuple(min, max, xs)) {
377
+ throw new TypeError(
378
+ `Expected an array of length in [${min}, ${max}], got an array of length ${actualLength}`,
379
+ );
380
+ }
381
+
382
+ return xs;
383
+ };
@@ -102,11 +102,6 @@ export function isFixedLengthTuple(
102
102
  }
103
103
  }
104
104
 
105
- const hasFixedLength = (
106
- len: SizeType.ArgArr,
107
- array: readonly unknown[],
108
- ): boolean => array.length === len;
109
-
110
105
  /**
111
106
  * Checks if an array has at least a specific length.
112
107
  *
@@ -150,11 +145,6 @@ export function isMinLengthTuple(
150
145
  }
151
146
  }
152
147
 
153
- const hasMinLength = (
154
- len: SizeType.ArgArr,
155
- array: readonly unknown[],
156
- ): boolean => array.length >= len;
157
-
158
148
  /**
159
149
  * Checks if an array has at most a specific length.
160
150
  *
@@ -198,11 +188,6 @@ export function isMaxLengthTuple(
198
188
  }
199
189
  }
200
190
 
201
- const hasMaxLength = (
202
- len: SizeType.ArgArr,
203
- array: readonly unknown[],
204
- ): boolean => array.length <= len;
205
-
206
191
  /**
207
192
  * Checks if an array's length is within a specific inclusive range.
208
193
  *
@@ -259,6 +244,21 @@ export function isBoundedLengthTuple(
259
244
  }
260
245
  }
261
246
 
247
+ const hasFixedLength = (
248
+ len: SizeType.ArgArr,
249
+ array: readonly unknown[],
250
+ ): boolean => array.length === len;
251
+
252
+ const hasMinLength = (
253
+ len: SizeType.ArgArr,
254
+ array: readonly unknown[],
255
+ ): boolean => array.length >= len;
256
+
257
+ const hasMaxLength = (
258
+ len: SizeType.ArgArr,
259
+ array: readonly unknown[],
260
+ ): boolean => array.length <= len;
261
+
262
262
  const isWithinBounds = (
263
263
  min: SizeType.ArgArr,
264
264
  max: SizeType.ArgArr,
@@ -55,12 +55,6 @@ export function set<E, const V = E>(
55
55
  }
56
56
  }
57
57
 
58
- const setImpl = <E, const V = E>(
59
- array: readonly E[],
60
- index: SizeType.ArgArr,
61
- newValue: V,
62
- ): readonly (E | V)[] => (array as readonly (E | V)[]).with(index, newValue);
63
-
64
58
  /**
65
59
  * Returns a new array with an element at the specified index updated by applying a function.
66
60
  *
@@ -111,14 +105,6 @@ export function toUpdated<E, V = E>(
111
105
  }
112
106
  }
113
107
 
114
- const toUpdatedImpl = <E, V = E>(
115
- array: readonly E[],
116
- index: SizeType.ArgArr,
117
- updater: (prev: E) => V,
118
- ): readonly (E | V)[] =>
119
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
120
- (array as readonly (E | V)[]).with(index, updater(array[index]!));
121
-
122
108
  /**
123
109
  * Returns a new array with a value inserted at the specified index.
124
110
  *
@@ -175,20 +161,6 @@ export function toInserted<E, const V = E>(
175
161
  }
176
162
  }
177
163
 
178
- const toInsertedImpl = <E, const V = E>(
179
- array: readonly E[],
180
- index: SizeType.ArgArrWithNegative,
181
- newValue: V,
182
- ): NonEmptyArray<E | V> =>
183
- // eslint-disable-next-line total-functions/no-unsafe-type-assertion
184
- (array as readonly (E | V)[]).toSpliced(
185
- index,
186
- 0,
187
- newValue,
188
- ) as unknown as NonEmptyArray<E | V>;
189
-
190
- type CastToNumber<T> = T extends number ? T : never;
191
-
192
164
  /**
193
165
  * Returns a new array with the element at the specified index removed.
194
166
  *
@@ -229,11 +201,6 @@ export function toRemoved<E>(
229
201
  }
230
202
  }
231
203
 
232
- const toRemovedImpl = <E,>(
233
- array: readonly E[],
234
- index: SizeType.ArgArrWithNegative,
235
- ): readonly E[] => array.toSpliced(index, 1);
236
-
237
204
  /**
238
205
  * Returns a new array with a value appended to the end.
239
206
  *
@@ -279,13 +246,6 @@ export function toPushed<const Ar extends readonly unknown[], const V>(
279
246
  }
280
247
  }
281
248
 
282
- const toPushedImpl = <const Ar extends readonly unknown[], const V>(
283
- array: Ar,
284
- newValue: V,
285
- ): readonly [...Ar, V] =>
286
- // eslint-disable-next-line total-functions/no-unsafe-type-assertion
287
- array.toSpliced(array.length, 0, newValue) as unknown as readonly [...Ar, V];
288
-
289
249
  /**
290
250
  * Returns a new array with a value prepended to the beginning.
291
251
  *
@@ -331,13 +291,6 @@ export function toUnshifted<Ar extends readonly unknown[], const V>(
331
291
  }
332
292
  }
333
293
 
334
- const toUnshiftedImpl = <Ar extends readonly unknown[], const V>(
335
- array: Ar,
336
- newValue: V,
337
- ): readonly [V, ...Ar] =>
338
- // eslint-disable-next-line total-functions/no-unsafe-type-assertion
339
- array.toSpliced(0, 0, newValue) as unknown as readonly [V, ...Ar];
340
-
341
294
  /**
342
295
  * Returns a new array with all elements replaced by the specified value.
343
296
  *
@@ -363,10 +316,10 @@ export function toFilled<
363
316
  // For an array or tuple that carries no length brand the homomorphic mapping
364
317
  // already covers every case the conditional spelled out — a fixed-length tuple
365
318
  // keeps its length, `readonly [A, ...A[]]` stays non-empty, and `readonly A[]`
366
- // stays unbounded. Stating it directly is what keeps this usable from a
367
- // caller that is itself generic over the array: a conditional a *generic* `Ar`
368
- // cannot decide stays deferred, and its branded branch is then not assignable
369
- // to the caller's own mapping.
319
+ // stays unbounded. Stating it directly is what keeps this usable from a caller
320
+ // that is itself generic over the array: a conditional a *generic* `Ar` cannot
321
+ // decide stays deferred, and its branded branch is then not assignable to the
322
+ // caller's own mapping.
370
323
  export function toFilled<const Ar extends readonly unknown[], const V>(
371
324
  array: Ar,
372
325
  value: V,
@@ -395,9 +348,6 @@ export function toFilled<E>(
395
348
  }
396
349
  }
397
350
 
398
- const toFilledImpl = <E,>(array: readonly E[], value: E): readonly E[] =>
399
- create(asPositiveUint32(array.length), value);
400
-
401
351
  /**
402
352
  * Returns a new array with elements in the specified range replaced by the specified value.
403
353
  *
@@ -479,6 +429,56 @@ export function toRangeFilled<E, const V>(
479
429
  }
480
430
  }
481
431
 
432
+ const setImpl = <E, const V = E>(
433
+ array: readonly E[],
434
+ index: SizeType.ArgArr,
435
+ newValue: V,
436
+ ): readonly (E | V)[] => (array as readonly (E | V)[]).with(index, newValue);
437
+
438
+ const toUpdatedImpl = <E, V = E>(
439
+ array: readonly E[],
440
+ index: SizeType.ArgArr,
441
+ updater: (prev: E) => V,
442
+ ): readonly (E | V)[] =>
443
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
444
+ (array as readonly (E | V)[]).with(index, updater(array[index]!));
445
+
446
+ const toInsertedImpl = <E, const V = E>(
447
+ array: readonly E[],
448
+ index: SizeType.ArgArrWithNegative,
449
+ newValue: V,
450
+ ): NonEmptyArray<E | V> =>
451
+ // eslint-disable-next-line total-functions/no-unsafe-type-assertion
452
+ (array as readonly (E | V)[]).toSpliced(
453
+ index,
454
+ 0,
455
+ newValue,
456
+ ) as unknown as NonEmptyArray<E | V>;
457
+
458
+ type CastToNumber<T> = T extends number ? T : never;
459
+
460
+ const toRemovedImpl = <E,>(
461
+ array: readonly E[],
462
+ index: SizeType.ArgArrWithNegative,
463
+ ): readonly E[] => array.toSpliced(index, 1);
464
+
465
+ const toPushedImpl = <const Ar extends readonly unknown[], const V>(
466
+ array: Ar,
467
+ newValue: V,
468
+ ): readonly [...Ar, V] =>
469
+ // eslint-disable-next-line total-functions/no-unsafe-type-assertion
470
+ array.toSpliced(array.length, 0, newValue) as unknown as readonly [...Ar, V];
471
+
472
+ const toUnshiftedImpl = <Ar extends readonly unknown[], const V>(
473
+ array: Ar,
474
+ newValue: V,
475
+ ): readonly [V, ...Ar] =>
476
+ // eslint-disable-next-line total-functions/no-unsafe-type-assertion
477
+ array.toSpliced(0, 0, newValue) as unknown as readonly [V, ...Ar];
478
+
479
+ const toFilledImpl = <E,>(array: readonly E[], value: E): readonly E[] =>
480
+ create(asPositiveUint32(array.length), value);
481
+
482
482
  const toRangeFilledImpl = <E, const V>(
483
483
  array: readonly E[],
484
484
  value: V,