ts-data-forge 13.0.0 → 14.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/README.md +1 -1
  2. package/dist/array/impl/array-utils-creation.d.mts +2 -2
  3. package/dist/array/impl/array-utils-creation.d.mts.map +1 -1
  4. package/dist/array/impl/array-utils-creation.mjs.map +1 -1
  5. package/dist/array/impl/array-utils-length-bounded-array-cast.d.mts +56 -29
  6. package/dist/array/impl/array-utils-length-bounded-array-cast.d.mts.map +1 -1
  7. package/dist/array/impl/array-utils-length-bounded-array-cast.mjs +23 -15
  8. package/dist/array/impl/array-utils-length-bounded-array-cast.mjs.map +1 -1
  9. package/dist/array/impl/array-utils-length-bounded-array-guard.d.mts +126 -28
  10. package/dist/array/impl/array-utils-length-bounded-array-guard.d.mts.map +1 -1
  11. package/dist/array/impl/array-utils-length-bounded-array-guard.mjs +39 -5
  12. package/dist/array/impl/array-utils-length-bounded-array-guard.mjs.map +1 -1
  13. package/dist/array/impl/array-utils-length-bounded-tuple-cast.d.mts +167 -0
  14. package/dist/array/impl/array-utils-length-bounded-tuple-cast.d.mts.map +1 -0
  15. package/dist/array/impl/array-utils-length-bounded-tuple-cast.mjs +87 -0
  16. package/dist/array/impl/array-utils-length-bounded-tuple-cast.mjs.map +1 -0
  17. package/dist/array/impl/array-utils-length-bounded-tuple-guard.d.mts +135 -0
  18. package/dist/array/impl/array-utils-length-bounded-tuple-guard.d.mts.map +1 -0
  19. package/dist/array/impl/array-utils-length-bounded-tuple-guard.mjs +41 -0
  20. package/dist/array/impl/array-utils-length-bounded-tuple-guard.mjs.map +1 -0
  21. package/dist/array/impl/array-utils-modification.d.mts +32 -18
  22. package/dist/array/impl/array-utils-modification.d.mts.map +1 -1
  23. package/dist/array/impl/array-utils-modification.mjs.map +1 -1
  24. package/dist/array/impl/array-utils-reducing-value.d.mts +3 -3
  25. package/dist/array/impl/array-utils-reducing-value.d.mts.map +1 -1
  26. package/dist/array/impl/array-utils-reducing-value.mjs +1 -1
  27. package/dist/array/impl/array-utils-reducing-value.mjs.map +1 -1
  28. package/dist/array/impl/array-utils-slicing.d.mts +11 -11
  29. package/dist/array/impl/array-utils-slicing.d.mts.map +1 -1
  30. package/dist/array/impl/array-utils-slicing.mjs +1 -1
  31. package/dist/array/impl/array-utils-slicing.mjs.map +1 -1
  32. package/dist/array/impl/array-utils-transformation.d.mts +35 -23
  33. package/dist/array/impl/array-utils-transformation.d.mts.map +1 -1
  34. package/dist/array/impl/array-utils-transformation.mjs +2 -2
  35. package/dist/array/impl/array-utils-transformation.mjs.map +1 -1
  36. package/dist/array/impl/array-utils-validation.d.mts +2 -124
  37. package/dist/array/impl/array-utils-validation.d.mts.map +1 -1
  38. package/dist/array/impl/array-utils-validation.mjs +1 -7
  39. package/dist/array/impl/array-utils-validation.mjs.map +1 -1
  40. package/dist/array/impl/index.d.mts +2 -0
  41. package/dist/array/impl/index.d.mts.map +1 -1
  42. package/dist/array/impl/index.mjs +5 -3
  43. package/dist/array/impl/index.mjs.map +1 -1
  44. package/dist/object/object.mjs +1 -1
  45. package/dist/string/str.d.mts +44 -44
  46. package/dist/string/str.d.mts.map +1 -1
  47. package/dist/string/str.mjs +17 -17
  48. package/dist/string/str.mjs.map +1 -1
  49. package/package.json +2 -2
  50. package/src/array/impl/array-utils-creation.mts +7 -3
  51. package/src/array/impl/array-utils-length-bounded-array-cast.mts +88 -50
  52. package/src/array/impl/array-utils-length-bounded-array-cast.test.mts +40 -13
  53. package/src/array/impl/array-utils-length-bounded-array-guard.mts +248 -39
  54. package/src/array/impl/array-utils-length-bounded-array-guard.test.mts +135 -24
  55. package/src/array/impl/array-utils-length-bounded-tuple-cast.mts +364 -0
  56. package/src/array/impl/array-utils-length-bounded-tuple-cast.test.mts +207 -0
  57. package/src/array/impl/array-utils-length-bounded-tuple-guard.mts +266 -0
  58. package/src/array/impl/array-utils-length-bounded-tuple-guard.test.mts +441 -0
  59. package/src/array/impl/array-utils-length-constraint-preservation.test.mts +287 -0
  60. package/src/array/impl/array-utils-modification.mts +72 -57
  61. package/src/array/impl/array-utils-modification.test.mts +93 -6
  62. package/src/array/impl/array-utils-reducing-value.mts +5 -5
  63. package/src/array/impl/array-utils-slicing.mts +65 -43
  64. package/src/array/impl/array-utils-slicing.test.mts +55 -0
  65. package/src/array/impl/array-utils-transformation.mts +66 -39
  66. package/src/array/impl/array-utils-transformation.test.mts +62 -16
  67. package/src/array/impl/array-utils-validation.mts +2 -162
  68. package/src/array/impl/array-utils-validation.test.mts +0 -371
  69. package/src/array/impl/index.mts +2 -0
  70. package/src/collections/queue.test.mts +1 -1
  71. package/src/string/str.mts +69 -69
  72. package/src/string/str.test.mts +40 -40
@@ -23,13 +23,14 @@ import {
23
23
  * structural tuple prefix (in-range indexed access without `undefined` under
24
24
  * `noUncheckedIndexedAccess`).
25
25
  *
26
- * Supports a curried overload: calling it with only `length` returns a
27
- * function that casts an array, which is convenient for `pipe`/`map`.
26
+ * The length argument comes first, matching the type-parameter order of
27
+ * `FixedLengthArray<Length, Elm>`. Omitting the array returns a function that
28
+ * casts one, which is convenient for `pipe`/`map`.
28
29
  *
29
30
  * @example
30
31
  *
31
32
  * ```ts
32
- * const rgb = Arr.asFixedLengthArray([255, 128, 0], 3);
33
+ * const rgb = Arr.asFixedLengthArray(3, [255, 128, 0]);
33
34
  *
34
35
  * const atMost5: MaxLengthArray<5, number> = rgb; // OK (3 <= 5)
35
36
  * const red: number = rgb[0]; // OK — no `undefined`
@@ -38,20 +39,20 @@ import {
38
39
  * const asRgb = Arr.asFixedLengthArray(3);
39
40
  * const green = asRgb([0, 255, 0]);
40
41
  *
41
- * // Arr.asFixedLengthArray([255, 128], 3); // throws TypeError
42
+ * // Arr.asFixedLengthArray(3, [255, 128]); // throws TypeError
42
43
  * ```
43
44
  *
44
- * @template Xs - The input array type (tuple types are preserved).
45
45
  * @template Length - The exact number of elements.
46
- * @param xs - The array to cast.
46
+ * @template Xs - The input array type (tuple types are preserved).
47
47
  * @param length - The exact number of elements.
48
+ * @param xs - The array to cast.
48
49
  * @returns `xs` typed as `FixedLengthArray<Length, Xs[number]> & Xs`.
49
50
  * @throws {TypeError} If `xs.length !== length`.
50
51
  */
51
52
  export function asFixedLengthArray<
52
- Xs extends readonly unknown[],
53
53
  Length extends SupportedLength,
54
- >(xs: Xs, length: Length): FixedLengthArray<Length, Xs[number]> & Xs;
54
+ Xs extends readonly unknown[],
55
+ >(length: Length, xs: Xs): FixedLengthArray<Length, Xs[number]> & Xs;
55
56
 
56
57
  // Curried version
57
58
  export function asFixedLengthArray<Length extends SupportedLength>(
@@ -62,7 +63,7 @@ export function asFixedLengthArray<Length extends SupportedLength>(
62
63
 
63
64
  export function asFixedLengthArray<E>(
64
65
  ...args:
65
- | readonly [xs: readonly E[], length: SupportedLength]
66
+ | readonly [length: SupportedLength, xs: readonly E[]]
66
67
  | readonly [length: SupportedLength]
67
68
  ): readonly E[] | ((xs: readonly E[]) => readonly E[]) {
68
69
  switch (args.length) {
@@ -70,17 +71,17 @@ export function asFixedLengthArray<E>(
70
71
  return asFixedLengthArrayImpl(...args);
71
72
 
72
73
  case 1:
73
- return (xs) => asFixedLengthArrayImpl(xs, ...args);
74
+ return (xs) => asFixedLengthArrayImpl(args[0], xs);
74
75
  }
75
76
  }
76
77
 
77
78
  const asFixedLengthArrayImpl = <E,>(
78
- xs: readonly E[],
79
79
  length: SupportedLength,
80
+ xs: readonly E[],
80
81
  ): readonly E[] => {
81
82
  const actualLength = xs.length;
82
83
 
83
- if (!isFixedLengthArray(xs, length)) {
84
+ if (!isFixedLengthArray(length, xs)) {
84
85
  throw new TypeError(
85
86
  `Expected an array of length ${length}, got an array of length ${actualLength}`,
86
87
  );
@@ -99,13 +100,14 @@ const asFixedLengthArrayImpl = <E,>(
99
100
  * structural tuple prefix (indexed access below `min(N, 10)` without
100
101
  * `undefined` under `noUncheckedIndexedAccess`).
101
102
  *
102
- * Supports a curried overload: calling it with only `minLength` returns a
103
- * function that casts an array, which is convenient for `pipe`/`map`.
103
+ * The length argument comes first, matching the type-parameter order of
104
+ * `MinLengthArray<MinLength, Elm>`. Omitting the array returns a function that
105
+ * casts one, which is convenient for `pipe`/`map`.
104
106
  *
105
107
  * @example
106
108
  *
107
109
  * ```ts
108
- * const history = Arr.asMinLengthArray([0, 1, 2, 3], 3);
110
+ * const history = Arr.asMinLengthArray(3, [0, 1, 2, 3]);
109
111
  *
110
112
  * const nonEmpty: MinLengthArray<1, number> = history; // OK (3 >= 1)
111
113
  * const first: number = history[0]; // OK — no `undefined`
@@ -114,20 +116,20 @@ const asFixedLengthArrayImpl = <E,>(
114
116
  * const asHistory = Arr.asMinLengthArray(3);
115
117
  * const next = asHistory([4, 5, 6, 7]);
116
118
  *
117
- * // Arr.asMinLengthArray([0], 3); // throws TypeError
119
+ * // Arr.asMinLengthArray(3, [0]); // throws TypeError
118
120
  * ```
119
121
  *
120
- * @template Xs - The input array type (tuple types are preserved).
121
122
  * @template MinLength - The minimum number of elements (inclusive).
122
- * @param xs - The array to cast.
123
+ * @template Xs - The input array type (tuple types are preserved).
123
124
  * @param minLength - The minimum number of elements (inclusive).
125
+ * @param xs - The array to cast.
124
126
  * @returns `xs` typed as `MinLengthArray<MinLength, Xs[number]> & Xs`.
125
127
  * @throws {TypeError} If `xs.length < minLength`.
126
128
  */
127
129
  export function asMinLengthArray<
128
- Xs extends readonly unknown[],
129
130
  MinLength extends SupportedLength,
130
- >(xs: Xs, minLength: MinLength): MinLengthArray<MinLength, Xs[number]> & Xs;
131
+ Xs extends readonly unknown[],
132
+ >(minLength: MinLength, xs: Xs): MinLengthArray<MinLength, Xs[number]> & Xs;
131
133
 
132
134
  // Curried version
133
135
  export function asMinLengthArray<MinLength extends SupportedLength>(
@@ -138,7 +140,7 @@ export function asMinLengthArray<MinLength extends SupportedLength>(
138
140
 
139
141
  export function asMinLengthArray<E>(
140
142
  ...args:
141
- | readonly [xs: readonly E[], minLength: SupportedLength]
143
+ | readonly [minLength: SupportedLength, xs: readonly E[]]
142
144
  | readonly [minLength: SupportedLength]
143
145
  ): readonly E[] | ((xs: readonly E[]) => readonly E[]) {
144
146
  switch (args.length) {
@@ -146,17 +148,17 @@ export function asMinLengthArray<E>(
146
148
  return asMinLengthArrayImpl(...args);
147
149
 
148
150
  case 1:
149
- return (xs) => asMinLengthArrayImpl(xs, ...args);
151
+ return (xs) => asMinLengthArrayImpl(args[0], xs);
150
152
  }
151
153
  }
152
154
 
153
155
  const asMinLengthArrayImpl = <E,>(
154
- xs: readonly E[],
155
156
  minLength: SupportedLength,
157
+ xs: readonly E[],
156
158
  ): readonly E[] => {
157
159
  const actualLength = xs.length;
158
160
 
159
- if (!isMinLengthArray(xs, minLength)) {
161
+ if (!isMinLengthArray(minLength, xs)) {
160
162
  throw new TypeError(
161
163
  `Expected an array of length >= ${minLength}, got an array of length ${actualLength}`,
162
164
  );
@@ -173,13 +175,14 @@ const asMinLengthArrayImpl = <E,>(
173
175
  * length is verified at runtime, and the original array type (e.g. tuple
174
176
  * types) is preserved via intersection.
175
177
  *
176
- * Supports a curried overload: calling it with only `maxLength` returns a
177
- * function that casts an array, which is convenient for `pipe`/`map`.
178
+ * The length argument comes first, matching the type-parameter order of
179
+ * `MaxLengthArray<MaxLength, Elm>`. Omitting the array returns a function that
180
+ * casts one, which is convenient for `pipe`/`map`.
178
181
  *
179
182
  * @example
180
183
  *
181
184
  * ```ts
182
- * const tags = Arr.asMaxLengthArray(['a', 'b', 'c'], 8);
185
+ * const tags = Arr.asMaxLengthArray(8, ['a', 'b', 'c']);
183
186
  *
184
187
  * const relaxed: MaxLengthArray<16, string> = tags; // OK (8 <= 16)
185
188
  *
@@ -187,20 +190,20 @@ const asMinLengthArrayImpl = <E,>(
187
190
  * const asTags = Arr.asMaxLengthArray(8);
188
191
  * const more = asTags(['d', 'e']);
189
192
  *
190
- * // Arr.asMaxLengthArray(['a', 'b', 'c'], 2); // throws TypeError
193
+ * // Arr.asMaxLengthArray(2, ['a', 'b', 'c']); // throws TypeError
191
194
  * ```
192
195
  *
193
- * @template Xs - The input array type (tuple types are preserved).
194
196
  * @template MaxLength - The maximum number of elements (inclusive).
195
- * @param xs - The array to cast.
197
+ * @template Xs - The input array type (tuple types are preserved).
196
198
  * @param maxLength - The maximum number of elements (inclusive).
199
+ * @param xs - The array to cast.
197
200
  * @returns `xs` typed as `MaxLengthArray<MaxLength, Xs[number]> & Xs`.
198
201
  * @throws {TypeError} If `xs.length > maxLength`.
199
202
  */
200
203
  export function asMaxLengthArray<
201
- Xs extends readonly unknown[],
202
204
  MaxLength extends SupportedLength,
203
- >(xs: Xs, maxLength: MaxLength): MaxLengthArray<MaxLength, Xs[number]> & Xs;
205
+ Xs extends readonly unknown[],
206
+ >(maxLength: MaxLength, xs: Xs): MaxLengthArray<MaxLength, Xs[number]> & Xs;
204
207
 
205
208
  // Curried version
206
209
  export function asMaxLengthArray<MaxLength extends SupportedLength>(
@@ -211,7 +214,7 @@ export function asMaxLengthArray<MaxLength extends SupportedLength>(
211
214
 
212
215
  export function asMaxLengthArray<E>(
213
216
  ...args:
214
- | readonly [xs: readonly E[], maxLength: SupportedLength]
217
+ | readonly [maxLength: SupportedLength, xs: readonly E[]]
215
218
  | readonly [maxLength: SupportedLength]
216
219
  ): readonly E[] | ((xs: readonly E[]) => readonly E[]) {
217
220
  switch (args.length) {
@@ -219,17 +222,17 @@ export function asMaxLengthArray<E>(
219
222
  return asMaxLengthArrayImpl(...args);
220
223
 
221
224
  case 1:
222
- return (xs) => asMaxLengthArrayImpl(xs, ...args);
225
+ return (xs) => asMaxLengthArrayImpl(args[0], xs);
223
226
  }
224
227
  }
225
228
 
226
229
  const asMaxLengthArrayImpl = <E,>(
227
- xs: readonly E[],
228
230
  maxLength: SupportedLength,
231
+ xs: readonly E[],
229
232
  ): readonly E[] => {
230
233
  const actualLength = xs.length;
231
234
 
232
- if (!isMaxLengthArray(xs, maxLength)) {
235
+ if (!isMaxLengthArray(maxLength, xs)) {
233
236
  throw new TypeError(
234
237
  `Expected an array of length <= ${maxLength}, got an array of length ${actualLength}`,
235
238
  );
@@ -248,14 +251,14 @@ const asMaxLengthArrayImpl = <E,>(
248
251
  * at runtime, and the original array type (e.g. tuple types) is preserved via
249
252
  * intersection.
250
253
  *
251
- * Supports a curried overload: calling it with only `minLength` and
252
- * `maxLength` returns a function that casts an array, which is convenient for
253
- * `pipe`/`map`.
254
+ * The length arguments come first, matching the type-parameter order of
255
+ * `BoundedLengthArray<MinLength, MaxLength, Elm>`. Omitting the array returns a
256
+ * function that casts one, which is convenient for `pipe`/`map`.
254
257
  *
255
258
  * @example
256
259
  *
257
260
  * ```ts
258
- * const selection = Arr.asBoundedLengthArray([1, 2, 3], 1, 5);
261
+ * const selection = Arr.asBoundedLengthArray(1, 5, [1, 2, 3]);
259
262
  *
260
263
  * const relaxed: BoundedLengthArray<0, 100, number> = selection; // OK
261
264
  *
@@ -263,27 +266,27 @@ const asMaxLengthArrayImpl = <E,>(
263
266
  * const asSelection = Arr.asBoundedLengthArray(1, 5);
264
267
  * const next = asSelection([4, 5]);
265
268
  *
266
- * // Arr.asBoundedLengthArray([], 1, 5); // throws TypeError
269
+ * // Arr.asBoundedLengthArray(1, 5, []); // throws TypeError
267
270
  * ```
268
271
  *
269
- * @template Xs - The input array type (tuple types are preserved).
270
272
  * @template MinLength - The minimum number of elements (inclusive).
271
273
  * @template MaxLength - The maximum number of elements (inclusive).
272
- * @param xs - The array to cast.
274
+ * @template Xs - The input array type (tuple types are preserved).
273
275
  * @param minLength - The minimum number of elements (inclusive).
274
276
  * @param maxLength - The maximum number of elements (inclusive).
277
+ * @param xs - The array to cast.
275
278
  * @returns `xs` typed as
276
279
  * `BoundedLengthArray<MinLength, MaxLength, Xs[number]> & Xs`.
277
280
  * @throws {TypeError} If `xs.length < minLength || xs.length > maxLength`.
278
281
  */
279
282
  export function asBoundedLengthArray<
280
- Xs extends readonly unknown[],
281
283
  MinLength extends SupportedLength,
282
284
  MaxLength extends SupportedLength,
285
+ Xs extends readonly unknown[],
283
286
  >(
284
- xs: Xs,
285
287
  minLength: MinLength,
286
288
  maxLength: MaxLength,
289
+ xs: Xs,
287
290
  ): BoundedLengthArray<MinLength, MaxLength, Xs[number]> & Xs;
288
291
 
289
292
  // Curried version
@@ -300,9 +303,9 @@ export function asBoundedLengthArray<
300
303
  export function asBoundedLengthArray<E>(
301
304
  ...args:
302
305
  | readonly [
303
- xs: readonly E[],
304
306
  minLength: SupportedLength,
305
307
  maxLength: SupportedLength,
308
+ xs: readonly E[],
306
309
  ]
307
310
  | readonly [minLength: SupportedLength, maxLength: SupportedLength]
308
311
  ): readonly E[] | ((xs: readonly E[]) => readonly E[]) {
@@ -311,18 +314,18 @@ export function asBoundedLengthArray<E>(
311
314
  return asBoundedLengthArrayImpl(...args);
312
315
 
313
316
  case 2:
314
- return (xs) => asBoundedLengthArrayImpl(xs, ...args);
317
+ return (xs) => asBoundedLengthArrayImpl(args[0], args[1], xs);
315
318
  }
316
319
  }
317
320
 
318
321
  const asBoundedLengthArrayImpl = <E,>(
319
- xs: readonly E[],
320
322
  minLength: SupportedLength,
321
323
  maxLength: SupportedLength,
324
+ xs: readonly E[],
322
325
  ): readonly E[] => {
323
326
  const actualLength = xs.length;
324
327
 
325
- if (!isBoundedLengthArray(xs, minLength, maxLength)) {
328
+ if (!isBoundedLengthArray(minLength, maxLength, xs)) {
326
329
  throw new TypeError(
327
330
  `Expected an array of length in [${minLength}, ${maxLength}], got an array of length ${actualLength}`,
328
331
  );
@@ -331,6 +334,41 @@ const asBoundedLengthArrayImpl = <E,>(
331
334
  return xs;
332
335
  };
333
336
 
337
+ /**
338
+ * Casts an array to `FixedLengthArray<0, E>` after checking that it is empty.
339
+ *
340
+ * `Arr.isEmpty` narrows to that same type, so this is its cast counterpart —
341
+ * the length-0 specialization of {@link asFixedLengthArray}. Use this instead
342
+ * of writing `xs as unknown as FixedLengthArray<0, E>`: the length is verified
343
+ * at runtime, and the original array type is preserved via intersection.
344
+ *
345
+ * @example
346
+ *
347
+ * ```ts
348
+ * const nothing = Arr.asEmptyArray([]);
349
+ *
350
+ * const atMost5: MaxLengthArray<5, never> = nothing; // OK (0 <= 5)
351
+ *
352
+ * // Arr.asEmptyArray([1]); // throws TypeError
353
+ * ```
354
+ *
355
+ * @template Xs - The input array type (tuple types are preserved).
356
+ * @param xs - The array to cast.
357
+ * @returns `xs` typed as `FixedLengthArray<0, Xs[number]> & Xs`.
358
+ * @throws {TypeError} If `xs` is not empty.
359
+ */
360
+ export const asEmptyArray = <Xs extends readonly unknown[]>(
361
+ xs: Xs,
362
+ ): FixedLengthArray<0, Xs[number]> & Xs => {
363
+ if (!isFixedLengthArray(0, xs)) {
364
+ throw new TypeError(
365
+ `Expected an empty array, got an array of length ${xs.length}`,
366
+ );
367
+ }
368
+
369
+ return xs;
370
+ };
371
+
334
372
  /**
335
373
  * Casts an array to `NonEmptyArray<E>` after checking that it has at least one
336
374
  * element.
@@ -360,7 +398,7 @@ const asBoundedLengthArrayImpl = <E,>(
360
398
  export const asNonEmptyArray = <Xs extends readonly unknown[]>(
361
399
  xs: Xs,
362
400
  ): NonEmptyArray<Xs[number]> & Xs => {
363
- if (!isMinLengthArray(xs, 1)) {
401
+ if (!isMinLengthArray(1, xs)) {
364
402
  throw new TypeError('Expected a non-empty array, got an empty array');
365
403
  }
366
404
 
@@ -8,6 +8,7 @@ import {
8
8
  import { expectType } from '../../expect-type.mjs';
9
9
  import {
10
10
  asBoundedLengthArray,
11
+ asEmptyArray,
11
12
  asFixedLengthArray,
12
13
  asMaxLengthArray,
13
14
  asMinLengthArray,
@@ -18,7 +19,7 @@ describe(asFixedLengthArray, () => {
18
19
  test('should return the input when the length matches exactly', () => {
19
20
  const xs: readonly number[] = [0, 1, 2, 3] as const;
20
21
 
21
- const casted = asFixedLengthArray(xs, 4);
22
+ const casted = asFixedLengthArray(4, xs);
22
23
 
23
24
  expect(casted).toBe(xs);
24
25
 
@@ -31,9 +32,9 @@ describe(asFixedLengthArray, () => {
31
32
  });
32
33
 
33
34
  test('should throw when the length does not match', () => {
34
- expect(() => asFixedLengthArray([0, 1, 2], 4)).toThrow(TypeError);
35
+ expect(() => asFixedLengthArray(4, [0, 1, 2])).toThrow(TypeError);
35
36
 
36
- expect(() => asFixedLengthArray([0, 1, 2], 4)).toThrow(
37
+ expect(() => asFixedLengthArray(4, [0, 1, 2])).toThrow(
37
38
  'Expected an array of length 4, got an array of length 3',
38
39
  );
39
40
  });
@@ -41,7 +42,7 @@ describe(asFixedLengthArray, () => {
41
42
  test('should preserve the original array type', () => {
42
43
  const tuple = [1, 2, 3] as const;
43
44
 
44
- const casted = asFixedLengthArray(tuple, 3);
45
+ const casted = asFixedLengthArray(3, tuple);
45
46
 
46
47
  expect(casted).toBe(tuple);
47
48
 
@@ -78,7 +79,7 @@ describe(asMinLengthArray, () => {
78
79
  test('should return the input when the array is long enough', () => {
79
80
  const xs: readonly number[] = [0, 1, 2, 3] as const;
80
81
 
81
- const casted = asMinLengthArray(xs, 3);
82
+ const casted = asMinLengthArray(3, xs);
82
83
 
83
84
  expect(casted).toBe(xs);
84
85
 
@@ -88,9 +89,9 @@ describe(asMinLengthArray, () => {
88
89
  });
89
90
 
90
91
  test('should throw when the array is too short', () => {
91
- expect(() => asMinLengthArray([0], 3)).toThrow(TypeError);
92
+ expect(() => asMinLengthArray(3, [0])).toThrow(TypeError);
92
93
 
93
- expect(() => asMinLengthArray([0], 3)).toThrow(
94
+ expect(() => asMinLengthArray(3, [0])).toThrow(
94
95
  'Expected an array of length >= 3, got an array of length 1',
95
96
  );
96
97
  });
@@ -120,7 +121,7 @@ describe(asMaxLengthArray, () => {
120
121
  test('should return the input when the array is short enough', () => {
121
122
  const xs: readonly number[] = [0, 1, 2] as const;
122
123
 
123
- const casted = asMaxLengthArray(xs, 8);
124
+ const casted = asMaxLengthArray(8, xs);
124
125
 
125
126
  expect(casted).toBe(xs);
126
127
 
@@ -130,9 +131,9 @@ describe(asMaxLengthArray, () => {
130
131
  });
131
132
 
132
133
  test('should throw when the array is too long', () => {
133
- expect(() => asMaxLengthArray([0, 1, 2], 2)).toThrow(TypeError);
134
+ expect(() => asMaxLengthArray(2, [0, 1, 2])).toThrow(TypeError);
134
135
 
135
- expect(() => asMaxLengthArray([0, 1, 2], 2)).toThrow(
136
+ expect(() => asMaxLengthArray(2, [0, 1, 2])).toThrow(
136
137
  'Expected an array of length <= 2, got an array of length 3',
137
138
  );
138
139
  });
@@ -162,7 +163,7 @@ describe(asBoundedLengthArray, () => {
162
163
  test('should return the input when the length is within the range', () => {
163
164
  const xs: readonly number[] = [1, 2, 3] as const;
164
165
 
165
- const casted = asBoundedLengthArray(xs, 1, 5);
166
+ const casted = asBoundedLengthArray(1, 5, xs);
166
167
 
167
168
  expect(casted).toBe(xs);
168
169
 
@@ -174,9 +175,9 @@ describe(asBoundedLengthArray, () => {
174
175
  });
175
176
 
176
177
  test('should throw when the length is out of the range', () => {
177
- expect(() => asBoundedLengthArray([], 1, 5)).toThrow(TypeError);
178
+ expect(() => asBoundedLengthArray(1, 5, [])).toThrow(TypeError);
178
179
 
179
- expect(() => asBoundedLengthArray([1, 2, 3, 4, 5, 6], 1, 5)).toThrow(
180
+ expect(() => asBoundedLengthArray(1, 5, [1, 2, 3, 4, 5, 6])).toThrow(
180
181
  'Expected an array of length in [1, 5], got an array of length 6',
181
182
  );
182
183
  });
@@ -242,3 +243,29 @@ describe(asNonEmptyArray, () => {
242
243
  expectType<typeof casted, NonEmptyArray<1 | 2 | 3>>('<=');
243
244
  });
244
245
  });
246
+
247
+ describe(asEmptyArray, () => {
248
+ test('casts an empty array to the branded empty type', () => {
249
+ const values: readonly number[] = [] as const;
250
+
251
+ const casted = asEmptyArray(values);
252
+
253
+ expectType<typeof casted, FixedLengthArray<0, number>>('<=');
254
+
255
+ assert.deepStrictEqual<readonly number[]>(casted, []);
256
+ });
257
+
258
+ test('is the same value it was handed', () => {
259
+ const values: readonly number[] = [] as const;
260
+
261
+ expect(asEmptyArray(values)).toBe(values);
262
+ });
263
+
264
+ test('throws when the array is not empty', () => {
265
+ expect(() => asEmptyArray([1])).toThrow(TypeError);
266
+
267
+ expect(() => asEmptyArray([1])).toThrow(
268
+ 'Expected an empty array, got an array of length 1',
269
+ );
270
+ });
271
+ });