Repository: dubzzz/fast-check
Pull request #1889 (2021-05-20 19:44:51)

🚚 Move typed-arrays arbitraries into /arbitrary
<!-- Context of the PR: short description and potentially linked issues -->

<!-- ...a few words to describe the content of this PR...               -->
<!-- ... -->

<!-- Type of PR: [ ] unchecked / [ ] checked -->
**_Category:_**

- [ ] ⚡️ Introduce new features
- [ ] 📝 Add or update documentation
- [ ] ✅ Add or update tests
- [ ] 🐛 Fix a bug
- [ ] 🏷️ Add or update types
- [x] _Other(s):_ moving code
<!-- Don't forget to add the gitmoji icon in the name of the PR -->
<!-- See: https://gitmoji.dev/                                  -->

<!-- Fixing bugs, adding feastures... may impact existing ones           -->
<!-- in order to track potential issues that could be related to your PR -->
<!-- please check the impacts and describe more precisely what to expect -->

**_Potential impacts:_**

<!-- Generated values: Can your change impact any of the existing generators in terms of generated values, if so which ones? when? -->
<!-- Shrink values:    Can your change impact any of the existing generators in terms of shrink values, if so which ones? when? -->
<!-- Performance:      Can it require some typings changes on user side? Please give more details -->
<!-- Typings:          Is there a potential performance impact? In which cases? -->
- [ ] Generated values
- [ ] Shrink values
- [ ] Performance
- [ ] Typings
- [ ] _Other(s):_ ...


codesandbox[bot]: This pull request is automatically built and testable in [CodeSandbox](https://codesandbox.io).

  To see build info of the built libraries, click [here](https://ci.codesandbox.io/status/dubzzz/fast-check/pr/1889/builds/132124) or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 8cfcd34deb8a0d52fb8bc507db1515e157b3d65f:

|Sandbox| Source |
|--|--|
|[Vanilla](https://codesandbox.io/s/vanilla-u4lp1)| Configuration |
|[fast-check-examples](https://codesandbox.io/s/fast-check-examples-cffqy)| Configuration |

codecov[bot]: # [Codecov](https://codecov.io/gh/dubzzz/fast-check/pull/1889?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN) Report
> Merging [#1889](https://codecov.io/gh/dubzzz/fast-check/pull/1889?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN) (8cfcd34) into [main](https://codecov.io/gh/dubzzz/fast-check/commit/44c14e80ad1c3395e674323a8ad89efff4a41046?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN) (44c14e8) will **decrease** coverage by `0.00%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/dubzzz/fast-check/pull/1889/graphs/tree.svg?width=650&height=150&src=pr&token=fRi2fJN730&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN)](https://codecov.io/gh/dubzzz/fast-check/pull/1889?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN)

```diff
@@            Coverage Diff             @@
##             main    #1889      +/-   ##
==========================================
- Coverage   97.49%   97.48%   -0.01%     
==========================================
  Files         148      160      +12     
  Lines        3948     4053     +105     
  Branches      764      781      +17     
==========================================
+ Hits         3849     3951     +102     
- Misses         95       98       +3     
  Partials        4        4              
```

| Flag | Coverage Δ | |
|---|---|---|
| unit-tests | `97.48% <100.00%> (-0.01%)` | :arrow_down: |
| unit-tests-10.x-Linux | `?` | |
| unit-tests-12.x-Linux | `?` | |
| unit-tests-14.x-Linux | `97.48% <100.00%> (-0.01%)` | :arrow_down: |
| unit-tests-16.x-Linux | `?` | |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/dubzzz/fast-check/pull/1889?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN) | Coverage Δ | |
|---|---|---|
| [...nternals/builders/TypedIntArrayArbitraryBuilder.ts](https://codecov.io/gh/dubzzz/fast-check/pull/1889/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#diff-c3JjL2FyYml0cmFyeS9faW50ZXJuYWxzL2J1aWxkZXJzL1R5cGVkSW50QXJyYXlBcmJpdHJhcnlCdWlsZGVyLnRz) | `100.00% <100.00%> (ø)` | |
| [src/arbitrary/float32Array.ts](https://codecov.io/gh/dubzzz/fast-check/pull/1889/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#diff-c3JjL2FyYml0cmFyeS9mbG9hdDMyQXJyYXkudHM=) | `100.00% <100.00%> (ø)` | |
| [src/arbitrary/float64Array.ts](https://codecov.io/gh/dubzzz/fast-check/pull/1889/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#diff-c3JjL2FyYml0cmFyeS9mbG9hdDY0QXJyYXkudHM=) | `100.00% <100.00%> (ø)` | |
| [src/arbitrary/int16Array.ts](https://codecov.io/gh/dubzzz/fast-check/pull/1889/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#diff-c3JjL2FyYml0cmFyeS9pbnQxNkFycmF5LnRz) | `100.00% <100.00%> (ø)` | |
| [src/arbitrary/int32Array.ts](https://codecov.io/gh/dubzzz/fast-check/pull/1889/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#diff-c3JjL2FyYml0cmFyeS9pbnQzMkFycmF5LnRz) | `100.00% <100.00%> (ø)` | |
| [src/arbitrary/int8Array.ts](https://codecov.io/gh/dubzzz/fast-check/pull/1889/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#diff-c3JjL2FyYml0cmFyeS9pbnQ4QXJyYXkudHM=) | `100.00% <100.00%> (ø)` | |
| [src/arbitrary/uint16Array.ts](https://codecov.io/gh/dubzzz/fast-check/pull/1889/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#diff-c3JjL2FyYml0cmFyeS91aW50MTZBcnJheS50cw==) | `100.00% <100.00%> (ø)` | |
| [src/arbitrary/uint32Array.ts](https://codecov.io/gh/dubzzz/fast-check/pull/1889/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#diff-c3JjL2FyYml0cmFyeS91aW50MzJBcnJheS50cw==) | `100.00% <100.00%> (ø)` | |
| [src/arbitrary/uint8Array.ts](https://codecov.io/gh/dubzzz/fast-check/pull/1889/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#diff-c3JjL2FyYml0cmFyeS91aW50OEFycmF5LnRz) | `100.00% <100.00%> (ø)` | |
| [src/arbitrary/uint8ClampedArray.ts](https://codecov.io/gh/dubzzz/fast-check/pull/1889/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#diff-c3JjL2FyYml0cmFyeS91aW50OENsYW1wZWRBcnJheS50cw==) | `100.00% <100.00%> (ø)` | |
| ... and [18 more](https://codecov.io/gh/dubzzz/fast-check/pull/1889/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/dubzzz/fast-check/pull/1889?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/dubzzz/fast-check/pull/1889?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN). Last update [44c14e8...8cfcd34](https://codecov.io/gh/dubzzz/fast-check/pull/1889?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN).


Patch:
diff --git a/src/arbitrary/_internals/builders/CompareFunctionArbitraryBuilder.ts b/src/arbitrary/_internals/builders/CompareFunctionArbitraryBuilder.ts
new file mode 100644
index 00000000..49a87939
--- /dev/null
+++ b/src/arbitrary/_internals/builders/CompareFunctionArbitraryBuilder.ts
@@ -0,0 +1,44 @@
+import { Arbitrary } from '../../../check/arbitrary/definition/Arbitrary';
+import { escapeForMultilineComments } from '../../../check/arbitrary/helpers/TextEscaper';
+import { cloneMethod } from '../../../check/symbols';
+import { hash } from '../../../utils/hash';
+import { stringify } from '../../../utils/stringify';
+import { integer } from '../../integer';
+import { tuple } from '../../tuple';
+
+/** @internal */
+export function buildCompareFunctionArbitrary<T, TOut>(
+  cmp: (hA: number, hB: number) => TOut
+): Arbitrary<(a: T, b: T) => TOut> {
+  return tuple(integer().noShrink(), integer(1, 0xffffffff).noShrink()).map(([seed, hashEnvSize]) => {
+    const producer = () => {
+      const recorded: { [key: string]: TOut } = {};
+      const f = (a: T, b: T) => {
+        const reprA = stringify(a);
+        const reprB = stringify(b);
+        const hA = hash(`${seed}${reprA}`) % hashEnvSize;
+        const hB = hash(`${seed}${reprB}`) % hashEnvSize;
+        const val = cmp(hA, hB);
+        recorded[`[${reprA},${reprB}]`] = val;
+        return val;
+      };
+      return Object.assign(f, {
+        toString: () => {
+          const seenValues = Object.keys(recorded)
+            .sort()
+            .map((k) => `${k} => ${stringify(recorded[k])}`)
+            .map((line) => `/* ${escapeForMultilineComments(line)} */`);
+          return `function(a, b) {
+  // With hash and stringify coming from fast-check${seenValues.length !== 0 ? `\n  ${seenValues.join('\n  ')}` : ''}
+  const cmp = ${cmp};
+  const hA = hash('${seed}' + stringify(a)) % ${hashEnvSize};
+  const hB = hash('${seed}' + stringify(b)) % ${hashEnvSize};
+  return cmp(hA, hB);
+}`;
+        },
+        [cloneMethod]: producer,
+      });
+    };
+    return producer();
+  });
+}
diff --git a/src/arbitrary/_internals/builders/TypedIntArrayArbitraryBuilder.ts b/src/arbitrary/_internals/builders/TypedIntArrayArbitraryBuilder.ts
new file mode 100644
index 00000000..d3390d79
--- /dev/null
+++ b/src/arbitrary/_internals/builders/TypedIntArrayArbitraryBuilder.ts
@@ -0,0 +1,62 @@
+import { Arbitrary } from '../../../check/arbitrary/definition/Arbitrary';
+import { array } from '../../array';
+
+/** @internal */
+type TypedIntArrayBuilderConstraints<TValue> = {
+  minLength?: number;
+  maxLength?: number;
+  min?: TValue;
+  max?: TValue;
+};
+
+/** @internal */
+export function typedIntArrayArbitraryArbitraryBuilder<TTypedArrayType, TValue>(
+  constraints: TypedIntArrayBuilderConstraints<TValue>,
+  defaultMin: TValue,
+  defaultMax: TValue,
+  TypedArrayClass: (new () => TTypedArrayType) & { from: (data: TValue[]) => TTypedArrayType },
+  arbitraryBuilder: (constraints: { min?: TValue; max?: TValue }) => Arbitrary<TValue>
+): Arbitrary<TTypedArrayType> {
+  const generatorName = TypedArrayClass.name;
+  const { min = defaultMin, max = defaultMax, ...arrayConstraints } = constraints;
+  if (min > max) {
+    throw new Error(`Invalid range passed to ${generatorName}: min must be lower than or equal to max`);
+  }
+  if (min < defaultMin) {
+    throw new Error(`Invalid min value passed to ${generatorName}: min must be greater than or equal to ${defaultMin}`);
+  }
+  if (max > defaultMax) {
+    throw new Error(`Invalid max value passed to ${generatorName}: max must be lower than or equal to ${defaultMax}`);
+  }
+  return array(arbitraryBuilder({ min, max }), arrayConstraints).map((data) => TypedArrayClass.from(data));
+}
+
+/**
+ * Constraints to be applied on typed arrays for integer values
+ * @remarks Since 2.9.0
+ * @public
+ */
+export type IntArrayConstraints = {
+  /**
+   * Lower bound of the generated array size
+   * @remarks Since 2.9.0
+   */
+  minLength?: number;
+  /**
+   * Upper bound of the generated array size
+   * @remarks Since 2.9.0
+   */
+  maxLength?: number;
+  /**
+   * Lower bound for the generated int (included)
+   * @defaultValue smallest possible value for this type
+   * @remarks Since 2.9.0
+   */
+  min?: number;
+  /**
+   * Upper bound for the generated int (included)
+   * @defaultValue highest possible value for this type
+   * @remarks Since 2.9.0
+   */
+  max?: number;
+};
diff --git a/src/arbitrary/compareBooleanFunc.ts b/src/arbitrary/compareBooleanFunc.ts
new file mode 100644
index 00000000..4511d411
--- /dev/null
+++ b/src/arbitrary/compareBooleanFunc.ts
@@ -0,0 +1,24 @@
+import { Arbitrary } from '../check/arbitrary/definition/Arbitrary';
+import { buildCompareFunctionArbitrary } from './_internals/builders/CompareFunctionArbitraryBuilder';
+
+/**
+ * For comparison boolean functions
+ *
+ * A comparison boolean function returns:
+ * - `true` whenever `a < b`
+ * - `false` otherwise (ie. `a = b` or `a > b`)
+ *
+ * @remarks Since 1.6.0
+ * @public
+ */
+export function compareBooleanFunc<T>(): Arbitrary<(a: T, b: T) => boolean> {
+  return buildCompareFunctionArbitrary(
+    Object.assign((hA: number, hB: number) => hA < hB, {
+      toString() {
+        // istanbul coverage tool may override the function for its needs (thus its string representation)
+        // assigning explicitly a toString representation avoids this issue
+        return '(hA, hB) => hA < hB';
+      },
+    })
+  );
+}
diff --git a/src/arbitrary/compareFunc.ts b/src/arbitrary/compareFunc.ts
new file mode 100644
index 00000000..fcc210b4
--- /dev/null
+++ b/src/arbitrary/compareFunc.ts
@@ -0,0 +1,29 @@
+import { Arbitrary } from '../check/arbitrary/definition/Arbitrary';
+import { buildCompareFunctionArbitrary } from './_internals/builders/CompareFunctionArbitraryBuilder';
+
+/**
+ * For comparison functions
+ *
+ * A comparison function returns:
+ * - negative value whenever `a < b`
+ * - positive value whenever `a > b`
+ * - zero whenever `a` and `b` are equivalent
+ *
+ * Comparison functions are transitive: `a < b and b < c => a < c`
+ *
+ * They also satisfy: `a < b <=> b > a` and `a = b <=> b = a`
+ *
+ * @remarks Since 1.6.0
+ * @public
+ */
+export function compareFunc<T>(): Arbitrary<(a: T, b: T) => number> {
+  return buildCompareFunctionArbitrary(
+    Object.assign((hA: number, hB: number) => hA - hB, {
+      toString() {
+        // istanbul coverage tool may override the function for its needs (thus its string representation)
+        // assigning explicitly a toString representation avoids this issue
+        return '(hA, hB) => hA - hB';
+      },
+    })
+  );
+}
diff --git a/src/arbitrary/float32Array.ts b/src/arbitrary/float32Array.ts
new file mode 100644
index 00000000..25335eb5
--- /dev/null
+++ b/src/arbitrary/float32Array.ts
@@ -0,0 +1,31 @@
+import { Arbitrary } from '../check/arbitrary/definition/Arbitrary';
+import { float } from '../check/arbitrary/FloatingPointArbitrary';
+import { FloatNextConstraints } from '../check/arbitrary/FloatNextArbitrary';
+import { array } from './array';
+
+/**
+ * Constraints to be applied on {@link float32Array}
+ * @remarks Since 2.9.0
+ * @public
+ */
+export type Float32ArrayConstraints = {
+  /**
+   * Lower bound of the generated array size
+   * @remarks Since 2.9.0
+   */
+  minLength?: number;
+  /**
+   * Upper bound of the generated array size
+   * @remarks Since 2.9.0
+   */
+  maxLength?: number;
+} & FloatNextConstraints;
+
+/**
+ * For Float32Array
+ * @remarks Since 2.9.0
+ * @public
+ */
+export function float32Array(constraints: Float32ArrayConstraints = {}): Arbitrary<Float32Array> {
+  return array(float({ ...constraints, next: true }), constraints).map((data) => Float32Array.from(data));
+}
diff --git a/src/arbitrary/float64Array.ts b/src/arbitrary/float64Array.ts
new file mode 100644
index 00000000..971546a7
--- /dev/null
+++ b/src/arbitrary/float64Array.ts
@@ -0,0 +1,31 @@
+import { Arbitrary } from '../check/arbitrary/definition/Arbitrary';
+import { DoubleNextConstraints } from '../check/arbitrary/DoubleNextArbitrary';
+import { double } from '../check/arbitrary/FloatingPointArbitrary';
+import { array } from './array';
+
+/**
+ * Constraints to be applied on {@link float64Array}
+ * @remarks Since 2.9.0
+ * @public
+ */
+export type Float64ArrayConstraints = {
+  /**
+   * Lower bound of the generated array size
+   * @remarks Since 2.9.0
+   */
+  minLength?: number;
+  /**
+   * Upper bound of the generated array size
+   * @remarks Since 2.9.0
+   */
+  maxLength?: number;
+} & DoubleNextConstraints;
+
+/**
+ * For Float64Array
+ * @remarks Since 2.9.0
+ * @public
+ */
+export function float64Array(constraints: Float64ArrayConstraints = {}): Arbitrary<Float64Array> {
+  return array(double({ ...constraints, next: true }), constraints).map((data) => Float64Array.from(data));
+}
diff --git a/src/arbitrary/func.ts b/src/arbitrary/func.ts
new file mode 100644
index 00000000..14eeaab6
--- /dev/null
+++ b/src/arbitrary/func.ts
@@ -0,0 +1,45 @@
+import { hash } from '../utils/hash';
+import { stringify } from '../utils/stringify';
+import { cloneMethod, hasCloneMethod } from '../check/symbols';
+import { array } from './array';
+import { Arbitrary } from '../check/arbitrary/definition/Arbitrary';
+import { integer } from './integer';
+import { tuple } from './tuple';
+import { escapeForMultilineComments } from '../check/arbitrary/helpers/TextEscaper';
+
+/**
+ * For pure functions
+ *
+ * @param arb - Arbitrary responsible to produce the values
+ *
+ * @remarks Since 1.6.0
+ * @public
+ */
+export function func<TArgs extends any[], TOut>(arb: Arbitrary<TOut>): Arbitrary<(...args: TArgs) => TOut> {
+  return tuple(array(arb, { minLength: 1 }), integer().noShrink()).map(([outs, seed]) => {
+    const producer = () => {
+      const recorded: { [key: string]: TOut } = {};
+      const f = (...args: TArgs) => {
+        const repr = stringify(args);
+        const val = outs[hash(`${seed}${repr}`) % outs.length];
+        recorded[repr] = val;
+        return hasCloneMethod(val) ? val[cloneMethod]() : val;
+      };
+      return Object.assign(f, {
+        toString: () => {
+          const seenValues = Object.keys(recorded)
+            .sort()
+            .map((k) => `${k} => ${stringify(recorded[k])}`)
+            .map((line) => `/* ${escapeForMultilineComments(line)} */`);
+          return `function(...args) {
+  // With hash and stringify coming from fast-check${seenValues.length !== 0 ? `\n  ${seenValues.join('\n  ')}` : ''}
+  const outs = ${stringify(outs)};
+  return outs[hash('${seed}' + stringify(args)) % outs.length];
+}`;
+        },
+        [cloneMethod]: producer,
+      });
+    };
+    return producer();
+  });
+}
diff --git a/src/arbitrary/int16Array.ts b/src/arbitrary/int16Array.ts
new file mode 100644
index 00000000..9ca84f54
--- /dev/null
+++ b/src/arbitrary/int16Array.ts
@@ -0,0 +1,16 @@
+import { Arbitrary } from '../check/arbitrary/definition/Arbitrary';
+import { integer } from './integer';
+import {
+  IntArrayConstraints,
+  typedIntArrayArbitraryArbitraryBuilder,
+} from './_internals/builders/TypedIntArrayArbitraryBuilder';
+
+/**
+ * For Int16Array
+ * @remarks Since 2.9.0
+ * @public
+ */
+export function int16Array(constraints: IntArrayConstraints = {}): Arbitrary<Int16Array> {
+  return typedIntArrayArbitraryArbitraryBuilder<Int16Array, number>(constraints, -32768, 32767, Int16Array, integer);
+}
+export { IntArrayConstraints };
diff --git a/src/arbitrary/int32Array.ts b/src/arbitrary/int32Array.ts
new file mode 100644
index 00000000..6827486b
--- /dev/null
+++ b/src/arbitrary/int32Array.ts
@@ -0,0 +1,22 @@
+import { Arbitrary } from '../check/arbitrary/definition/Arbitrary';
+import { integer } from './integer';
+import {
+  IntArrayConstraints,
+  typedIntArrayArbitraryArbitraryBuilder,
+} from './_internals/builders/TypedIntArrayArbitraryBuilder';
+
+/**
+ * For Int32Array
+ * @remarks Since 2.9.0
+ * @public
+ */
+export function int32Array(constraints: IntArrayConstraints = {}): Arbitrary<Int32Array> {
+  return typedIntArrayArbitraryArbitraryBuilder<Int32Array, number>(
+    constraints,
+    -0x80000000,
+    0x7fffffff,
+    Int32Array,
+    integer
+  );
+}
+export { IntArrayConstraints };
diff --git a/src/arbitrary/int8Array.ts b/src/arbitrary/int8Array.ts
new file mode 100644
index 00000000..ec4c6d5d
--- /dev/null
+++ b/src/arbitrary/int8Array.ts
@@ -0,0 +1,16 @@
+import { Arbitrary } from '../check/arbitrary/definition/Arbitrary';
+import { integer } from './integer';
+import {
+  IntArrayConstraints,
+  typedIntArrayArbitraryArbitraryBuilder,
+} from './_internals/builders/TypedIntArrayArbitraryBuilder';
+
+/**
+ * For Int8Array
+ * @remarks Since 2.9.0
+ * @public
+ */
+export function int8Array(constraints: IntArrayConstraints = {}): Arbitrary<Int8Array> {
+  return typedIntArrayArbitraryArbitraryBuilder<Int8Array, number>(constraints, -128, 127, Int8Array, integer);
+}
+export { IntArrayConstraints };
diff --git a/src/arbitrary/uint16Array.ts b/src/arbitrary/uint16Array.ts
new file mode 100644
index 00000000..b89fc91b
--- /dev/null
+++ b/src/arbitrary/uint16Array.ts
@@ -0,0 +1,16 @@
+import { Arbitrary } from '../check/arbitrary/definition/Arbitrary';
+import { integer } from './integer';
+import {
+  IntArrayConstraints,
+  typedIntArrayArbitraryArbitraryBuilder,
+} from './_internals/builders/TypedIntArrayArbitraryBuilder';
+
+/**
+ * For Uint16Array
+ * @remarks Since 2.9.0
+ * @public
+ */
+export function uint16Array(constraints: IntArrayConstraints = {}): Arbitrary<Uint16Array> {
+  return typedIntArrayArbitraryArbitraryBuilder<Uint16Array, number>(constraints, 0, 65535, Uint16Array, integer);
+}
+export { IntArrayConstraints };
diff --git a/src/arbitrary/uint32Array.ts b/src/arbitrary/uint32Array.ts
new file mode 100644
index 00000000..01be44f7
--- /dev/null
+++ b/src/arbitrary/uint32Array.ts
@@ -0,0 +1,16 @@
+import { Arbitrary } from '../check/arbitrary/definition/Arbitrary';
+import { integer } from './integer';
+import {
+  IntArrayConstraints,
+  typedIntArrayArbitraryArbitraryBuilder,
+} from './_internals/builders/TypedIntArrayArbitraryBuilder';
+
+/**
+ * For Uint32Array
+ * @remarks Since 2.9.0
+ * @public
+ */
+export function uint32Array(constraints: IntArrayConstraints = {}): Arbitrary<Uint32Array> {
+  return typedIntArrayArbitraryArbitraryBuilder<Uint32Array, number>(constraints, 0, 0xffffffff, Uint32Array, integer);
+}
+export { IntArrayConstraints };
diff --git a/src/arbitrary/uint8Array.ts b/src/arbitrary/uint8Array.ts
new file mode 100644
index 00000000..4af736f4
--- /dev/null
+++ b/src/arbitrary/uint8Array.ts
@@ -0,0 +1,16 @@
+import { Arbitrary } from '../check/arbitrary/definition/Arbitrary';
+import { integer } from './integer';
+import {
+  IntArrayConstraints,
+  typedIntArrayArbitraryArbitraryBuilder,
+} from './_internals/builders/TypedIntArrayArbitraryBuilder';
+
+/**
+ * For Uint8Array
+ * @remarks Since 2.9.0
+ * @public
+ */
+export function uint8Array(constraints: IntArrayConstraints = {}): Arbitrary<Uint8Array> {
+  return typedIntArrayArbitraryArbitraryBuilder<Uint8Array, number>(constraints, 0, 255, Uint8Array, integer);
+}
+export { IntArrayConstraints };
diff --git a/src/arbitrary/uint8ClampedArray.ts b/src/arbitrary/uint8ClampedArray.ts
new file mode 100644
index 00000000..b6451e20
--- /dev/null
+++ b/src/arbitrary/uint8ClampedArray.ts
@@ -0,0 +1,22 @@
+import { Arbitrary } from '../check/arbitrary/definition/Arbitrary';
+import { integer } from './integer';
+import {
+  IntArrayConstraints,
+  typedIntArrayArbitraryArbitraryBuilder,
+} from './_internals/builders/TypedIntArrayArbitraryBuilder';
+
+/**
+ * For Uint8ClampedArray
+ * @remarks Since 2.9.0
+ * @public
+ */
+export function uint8ClampedArray(constraints: IntArrayConstraints = {}): Arbitrary<Uint8ClampedArray> {
+  return typedIntArrayArbitraryArbitraryBuilder<Uint8ClampedArray, number>(
+    constraints,
+    0,
+    255,
+    Uint8ClampedArray,
+    integer
+  );
+}
+export { IntArrayConstraints };
diff --git a/src/check/arbitrary/FunctionArbitrary.ts b/src/check/arbitrary/FunctionArbitrary.ts
deleted file mode 100644
index efd78601..00000000
--- a/src/check/arbitrary/FunctionArbitrary.ts
+++ /dev/null
@@ -1,129 +0,0 @@
-import { hash } from '../../utils/hash';
-import { stringify } from '../../utils/stringify';
-import { cloneMethod, hasCloneMethod } from '../symbols';
-import { array } from '../../arbitrary/array';
-import { Arbitrary } from './definition/Arbitrary';
-import { integer } from '../../arbitrary/integer';
-import { tuple } from '../../arbitrary/tuple';
-import { escapeForMultilineComments } from './helpers/TextEscaper';
-
-/**
- * For pure functions
- *
- * @param arb - Arbitrary responsible to produce the values
- *
- * @remarks Since 1.6.0
- * @public
- */
-export function func<TArgs extends any[], TOut>(arb: Arbitrary<TOut>): Arbitrary<(...args: TArgs) => TOut> {
-  return tuple(array(arb, { minLength: 1 }), integer().noShrink()).map(([outs, seed]) => {
-    const producer = () => {
-      const recorded: { [key: string]: TOut } = {};
-      const f = (...args: TArgs) => {
-        const repr = stringify(args);
-        const val = outs[hash(`${seed}${repr}`) % outs.length];
-        recorded[repr] = val;
-        return hasCloneMethod(val) ? val[cloneMethod]() : val;
-      };
-      return Object.assign(f, {
-        toString: () => {
-          const seenValues = Object.keys(recorded)
-            .sort()
-            .map((k) => `${k} => ${stringify(recorded[k])}`)
-            .map((line) => `/* ${escapeForMultilineComments(line)} */`);
-          return `function(...args) {
-  // With hash and stringify coming from fast-check${seenValues.length !== 0 ? `\n  ${seenValues.join('\n  ')}` : ''}
-  const outs = ${stringify(outs)};
-  return outs[hash('${seed}' + stringify(args)) % outs.length];
-}`;
-        },
-        [cloneMethod]: producer,
-      });
-    };
-    return producer();
-  });
-}
-
-/** @internal */
-function compareFuncImplem<T, TOut>(cmp: (hA: number, hB: number) => TOut): Arbitrary<(a: T, b: T) => TOut> {
-  return tuple(integer().noShrink(), integer(1, 0xffffffff).noShrink()).map(([seed, hashEnvSize]) => {
-    const producer = () => {
-      const recorded: { [key: string]: TOut } = {};
-      const f = (a: T, b: T) => {
-        const reprA = stringify(a);
-        const reprB = stringify(b);
-        const hA = hash(`${seed}${reprA}`) % hashEnvSize;
-        const hB = hash(`${seed}${reprB}`) % hashEnvSize;
-        const val = cmp(hA, hB);
-        recorded[`[${reprA},${reprB}]`] = val;
-        return val;
-      };
-      return Object.assign(f, {
-        toString: () => {
-          const seenValues = Object.keys(recorded)
-            .sort()
-            .map((k) => `${k} => ${stringify(recorded[k])}`)
-            .map((line) => `/* ${escapeForMultilineComments(line)} */`);
-          return `function(a, b) {
-  // With hash and stringify coming from fast-check${seenValues.length !== 0 ? `\n  ${seenValues.join('\n  ')}` : ''}
-  const cmp = ${cmp};
-  const hA = hash('${seed}' + stringify(a)) % ${hashEnvSize};
-  const hB = hash('${seed}' + stringify(b)) % ${hashEnvSize};
-  return cmp(hA, hB);
-}`;
-        },
-        [cloneMethod]: producer,
-      });
-    };
-    return producer();
-  });
-}
-
-/**
- * For comparison functions
- *
- * A comparison function returns:
- * - negative value whenever `a < b`
- * - positive value whenever `a > b`
- * - zero whenever `a` and `b` are equivalent
- *
- * Comparison functions are transitive: `a < b and b < c => a < c`
- *
- * They also satisfy: `a < b <=> b > a` and `a = b <=> b = a`
- *
- * @remarks Since 1.6.0
- * @public
- */
-export function compareFunc<T>(): Arbitrary<(a: T, b: T) => number> {
-  return compareFuncImplem(
-    Object.assign((hA: number, hB: number) => hA - hB, {
-      toString() {
-        // istanbul coverage tool may override the function for its needs (thus its string representation)
-        // assigning explicitly a toString representation avoids this issue
-        return '(hA, hB) => hA - hB';
-      },
-    })
-  );
-}
-
-/**
- * For comparison boolean functions
- *
- * A comparison boolean function returns:
- * - `true` whenever `a < b`
- * - `false` otherwise (ie. `a = b` or `a > b`)
- *
- * @remarks Since 1.6.0
- * @public
- */
-export function compareBooleanFunc<T>(): Arbitrary<(a: T, b: T) => boolean> {
-  return compareFuncImplem(
-    Object.assign((hA: number, hB: number) => hA < hB, {
-      toString() {
-        // istanbul coverage tool may override the function for its needs (thus its string representation)
-        // assigning explicitly a toString representation avoids this issue
-        return '(hA, hB) => hA < hB';
-      },
-    })
-  );
-}
diff --git a/src/check/arbitrary/ObjectArbitrary.ts b/src/check/arbitrary/ObjectArbitrary.ts
index 2684b3d5..be084233 100644
--- a/src/check/arbitrary/ObjectArbitrary.ts
+++ b/src/check/arbitrary/ObjectArbitrary.ts
@@ -16,17 +16,15 @@ import { unicodeString } from '../../arbitrary/unicodeString';
 import { tuple } from '../../arbitrary/tuple';
 import { bigInt } from '../../arbitrary/bigInt';
 import { date } from '../../arbitrary/date';
-import {
-  float32Array,
-  float64Array,
-  int16Array,
-  int32Array,
-  int8Array,
-  uint16Array,
-  uint32Array,
-  uint8Array,
-  uint8ClampedArray,
-} from './TypedArrayArbitrary';
+import { float32Array } from '../../arbitrary/float32Array';
+import { float64Array } from '../../arbitrary/float64Array';
+import { int16Array } from '../../arbitrary/int16Array';
+import { int32Array } from '../../arbitrary/int32Array';
+import { int8Array } from '../../arbitrary/int8Array';
+import { uint16Array } from '../../arbitrary/uint16Array';
+import { uint32Array } from '../../arbitrary/uint32Array';
+import { uint8Array } from '../../arbitrary/uint8Array';
+import { uint8ClampedArray } from '../../arbitrary/uint8ClampedArray';
 import { sparseArray } from './SparseArrayArbitrary';
 import { keyValuePairsToObjectMapper } from '../../arbitrary/_internals/mappers/KeyValuePairsToObject';
 
diff --git a/src/check/arbitrary/TypedArrayArbitrary.ts b/src/check/arbitrary/TypedArrayArbitrary.ts
deleted file mode 100644
index 60cf1696..00000000
--- a/src/check/arbitrary/TypedArrayArbitrary.ts
+++ /dev/null
@@ -1,183 +0,0 @@
-import { array } from '../../arbitrary/array';
-import { Arbitrary } from './definition/Arbitrary';
-import { DoubleNextConstraints } from './DoubleNextArbitrary';
-import { double, float } from './FloatingPointArbitrary';
-import { FloatNextConstraints } from './FloatNextArbitrary';
-import { integer } from '../../arbitrary/integer';
-
-/** @internal */
-type TypedIntArrayBuilderConstraints<TValue> = {
-  minLength?: number;
-  maxLength?: number;
-  min?: TValue;
-  max?: TValue;
-};
-
-/** @internal */
-function typedIntArrayBuilder<TTypedArrayType, TValue>(
-  constraints: TypedIntArrayBuilderConstraints<TValue>,
-  defaultMin: TValue,
-  defaultMax: TValue,
-  TypedArrayClass: (new () => TTypedArrayType) & { from: (data: TValue[]) => TTypedArrayType },
-  arbitraryBuilder: (constraints: { min?: TValue; max?: TValue }) => Arbitrary<TValue>
-) {
-  const generatorName = TypedArrayClass.name;
-  const { min = defaultMin, max = defaultMax, ...arrayConstraints } = constraints;
-  if (min > max) {
-    throw new Error(`Invalid range passed to ${generatorName}: min must be lower than or equal to max`);
-  }
-  if (min < defaultMin) {
-    throw new Error(`Invalid min value passed to ${generatorName}: min must be greater than or equal to ${defaultMin}`);
-  }
-  if (max > defaultMax) {
-    throw new Error(`Invalid max value passed to ${generatorName}: max must be lower than or equal to ${defaultMax}`);
-  }
-  return array(arbitraryBuilder({ min, max }), arrayConstraints).map((data) => TypedArrayClass.from(data));
-}
-
-/**
- * Constraints to be applied on typed arrays for integer values
- * @remarks Since 2.9.0
- * @public
- */
-export type IntArrayConstraints = {
-  /**
-   * Lower bound of the generated array size
-   * @remarks Since 2.9.0
-   */
-  minLength?: number;
-  /**
-   * Upper bound of the generated array size
-   * @remarks Since 2.9.0
-   */
-  maxLength?: number;
-  /**
-   * Lower bound for the generated int (included)
-   * @defaultValue smallest possible value for this type
-   * @remarks Since 2.9.0
-   */
-  min?: number;
-  /**
-   * Upper bound for the generated int (included)
-   * @defaultValue highest possible value for this type
-   * @remarks Since 2.9.0
-   */
-  max?: number;
-};
-
-/**
- * For Int8Array
- * @remarks Since 2.9.0
- * @public
- */
-export function int8Array(constraints: IntArrayConstraints = {}): Arbitrary<Int8Array> {
-  return typedIntArrayBuilder<Int8Array, number>(constraints, -128, 127, Int8Array, integer);
-}
-
-/**
- * For Uint8Array
- * @remarks Since 2.9.0
- * @public
- */
-export function uint8Array(constraints: IntArrayConstraints = {}): Arbitrary<Uint8Array> {
-  return typedIntArrayBuilder<Uint8Array, number>(constraints, 0, 255, Uint8Array, integer);
-}
-
-/**
- * For Uint8ClampedArray
- * @remarks Since 2.9.0
- * @public
- */
-export function uint8ClampedArray(constraints: IntArrayConstraints = {}): Arbitrary<Uint8ClampedArray> {
-  return typedIntArrayBuilder<Uint8ClampedArray, number>(constraints, 0, 255, Uint8ClampedArray, integer);
-}
-
-/**
- * For Int16Array
- * @remarks Since 2.9.0
- * @public
- */
-export function int16Array(constraints: IntArrayConstraints = {}): Arbitrary<Int16Array> {
-  return typedIntArrayBuilder<Int16Array, number>(constraints, -32768, 32767, Int16Array, integer);
-}
-
-/**
- * For Uint16Array
- * @remarks Since 2.9.0
- * @public
- */
-export function uint16Array(constraints: IntArrayConstraints = {}): Arbitrary<Uint16Array> {
-  return typedIntArrayBuilder<Uint16Array, number>(constraints, 0, 65535, Uint16Array, integer);
-}
-
-/**
- * For Int32Array
- * @remarks Since 2.9.0
- * @public
- */
-export function int32Array(constraints: IntArrayConstraints = {}): Arbitrary<Int32Array> {
-  return typedIntArrayBuilder<Int32Array, number>(constraints, -0x80000000, 0x7fffffff, Int32Array, integer);
-}
-
-/**
- * For Uint32Array
- * @remarks Since 2.9.0
- * @public
- */
-export function uint32Array(constraints: IntArrayConstraints = {}): Arbitrary<Uint32Array> {
-  return typedIntArrayBuilder<Uint32Array, number>(constraints, 0, 0xffffffff, Uint32Array, integer);
-}
-
-/**
- * Constraints to be applied on {@link float32Array}
- * @remarks Since 2.9.0
- * @public
- */
-export type Float32ArrayConstraints = {
-  /**
-   * Lower bound of the generated array size
-   * @remarks Since 2.9.0
-   */
-  minLength?: number;
-  /**
-   * Upper bound of the generated array size
-   * @remarks Since 2.9.0
-   */
-  maxLength?: number;
-} & FloatNextConstraints;
-
-/**
- * For Float32Array
- * @remarks Since 2.9.0
- * @public
- */
-export function float32Array(constraints: Float32ArrayConstraints = {}): Arbitrary<Float32Array> {
-  return array(float({ ...constraints, next: true }), constraints).map((data) => Float32Array.from(data));
-}
-
-/**
- * Constraints to be applied on {@link float64Array}
- * @remarks Since 2.9.0
- * @public
- */
-export type Float64ArrayConstraints = {
-  /**
-   * Lower bound of the generated array size
-   * @remarks Since 2.9.0
-   */
-  minLength?: number;
-  /**
-   * Upper bound of the generated array size
-   * @remarks Since 2.9.0
-   */
-  maxLength?: number;
-} & DoubleNextConstraints;
-
-/**
- * For Float64Array
- * @remarks Since 2.9.0
- * @public
- */
-export function float64Array(constraints: Float64ArrayConstraints = {}): Arbitrary<Float64Array> {
-  return array(double({ ...constraints, next: true }), constraints).map((data) => Float64Array.from(data));
-}
diff --git a/src/fast-check-default.ts b/src/fast-check-default.ts
index 5947e9fb..77090f82 100644
--- a/src/fast-check-default.ts
+++ b/src/fast-check-default.ts
@@ -46,7 +46,9 @@ import { dictionary } from './arbitrary/dictionary';
 import { emailAddress } from './check/arbitrary/EmailArbitrary';
 import { double, float, DoubleConstraints, FloatConstraints } from './check/arbitrary/FloatingPointArbitrary';
 import { frequency, WeightedArbitrary, FrequencyValue, FrequencyContraints } from './arbitrary/frequency';
-import { compareBooleanFunc, compareFunc, func } from './check/arbitrary/FunctionArbitrary';
+import { compareBooleanFunc } from './arbitrary/compareBooleanFunc';
+import { compareFunc } from './arbitrary/compareFunc';
+import { func } from './arbitrary/func';
 import { domain } from './check/arbitrary/HostArbitrary';
 import { integer, IntegerConstraints } from './arbitrary/integer';
 import { maxSafeInteger } from './arbitrary/maxSafeInteger';
@@ -141,20 +143,15 @@ import { CommandsContraints } from './check/model/commands/CommandsContraints';
 import { PreconditionFailure } from './check/precondition/PreconditionFailure';
 import { RandomType } from './check/runner/configuration/RandomType';
 import { FloatNextConstraints } from './check/arbitrary/FloatNextArbitrary';
-import {
-  float32Array,
-  float64Array,
-  Float32ArrayConstraints,
-  int16Array,
-  int32Array,
-  int8Array,
-  IntArrayConstraints,
-  uint16Array,
-  uint32Array,
-  uint8Array,
-  uint8ClampedArray,
-  Float64ArrayConstraints,
-} from './check/arbitrary/TypedArrayArbitrary';
+import { int8Array, IntArrayConstraints } from './arbitrary/int8Array';
+import { int16Array } from './arbitrary/int16Array';
+import { int32Array } from './arbitrary/int32Array';
+import { uint8Array } from './arbitrary/uint8Array';
+import { uint8ClampedArray } from './arbitrary/uint8ClampedArray';
+import { uint16Array } from './arbitrary/uint16Array';
+import { uint32Array } from './arbitrary/uint32Array';
+import { float32Array, Float32ArrayConstraints } from './arbitrary/float32Array';
+import { float64Array, Float64ArrayConstraints } from './arbitrary/float64Array';
 import { sparseArray, SparseArrayConstraints } from './check/arbitrary/SparseArrayArbitrary';
 import { DoubleNextConstraints } from './check/arbitrary/DoubleNextArbitrary';
 import { NextArbitrary } from './check/arbitrary/definition/NextArbitrary';


Test patch:
diff --git a/test/unit/check/arbitrary/FunctionArbitrary.spec.ts b/test/unit/arbitrary/FunctionArbitrary.spec.ts
similarity index 95%
rename from test/unit/check/arbitrary/FunctionArbitrary.spec.ts
rename to test/unit/arbitrary/FunctionArbitrary.spec.ts
index e1ab5d51..b54d7fcb 100644
--- a/test/unit/check/arbitrary/FunctionArbitrary.spec.ts
+++ b/test/unit/arbitrary/FunctionArbitrary.spec.ts
@@ -1,15 +1,17 @@
-import * as fc from '../../../../lib/fast-check';
+import * as fc from '../../../lib/fast-check';
 
-import { func, compareFunc, compareBooleanFunc } from '../../../../src/check/arbitrary/FunctionArbitrary';
-import { context } from '../../../../src/arbitrary/context';
-import { integer } from '../../../../src/arbitrary/integer';
-import { hasCloneMethod, cloneMethod } from '../../../../src/check/symbols';
-import { hash } from '../../../../src/utils/hash';
-import { stringify } from '../../../../src/utils/stringify';
+import { compareBooleanFunc } from '../../../src/arbitrary/compareBooleanFunc';
+import { compareFunc } from '../../../src/arbitrary/compareFunc';
+import { func } from '../../../src/arbitrary/func';
+import { context } from '../../../src/arbitrary/context';
+import { integer } from '../../../src/arbitrary/integer';
+import { hasCloneMethod, cloneMethod } from '../../../src/check/symbols';
+import { hash } from '../../../src/utils/hash';
+import { stringify } from '../../../src/utils/stringify';
 
-import * as genericHelper from './generic/GenericArbitraryHelper';
+import * as genericHelper from '../check/arbitrary/generic/GenericArbitraryHelper';
 
-import * as stubRng from '../../stubs/generators';
+import * as stubRng from '../stubs/generators';
 
 const forceClone = <T>(instance: T) => {
   if (!hasCloneMethod(instance)) throw new Error('Missing [cloneMethod]');
diff --git a/test/unit/check/arbitrary/TypedArrayArbitrary.utest.spec.ts b/test/unit/arbitrary/TypedArrayArbitrary.utest.spec.ts
similarity index 85%
rename from test/unit/check/arbitrary/TypedArrayArbitrary.utest.spec.ts
rename to test/unit/arbitrary/TypedArrayArbitrary.utest.spec.ts
index 7b7274aa..17685f36 100644
--- a/test/unit/check/arbitrary/TypedArrayArbitrary.utest.spec.ts
+++ b/test/unit/arbitrary/TypedArrayArbitrary.utest.spec.ts
@@ -1,21 +1,18 @@
-import * as fc from '../../../../lib/fast-check';
-import {
-  int16Array,
-  int32Array,
-  int8Array,
-  IntArrayConstraints,
-  uint16Array,
-  uint32Array,
-  uint8Array,
-  uint8ClampedArray,
-} from '../../../../src/check/arbitrary/TypedArrayArbitrary';
-import { Arbitrary } from '../../../../src/check/arbitrary/definition/Arbitrary';
+import * as fc from '../../../lib/fast-check';
+import { int8Array, IntArrayConstraints } from '../../../src/arbitrary/int8Array';
+import { int16Array } from '../../../src/arbitrary/int16Array';
+import { int32Array } from '../../../src/arbitrary/int32Array';
+import { uint8Array } from '../../../src/arbitrary/uint8Array';
+import { uint8ClampedArray } from '../../../src/arbitrary/uint8ClampedArray';
+import { uint16Array } from '../../../src/arbitrary/uint16Array';
+import { uint32Array } from '../../../src/arbitrary/uint32Array';
+import { Arbitrary } from '../../../src/check/arbitrary/definition/Arbitrary';
 
 import { mocked } from 'ts-jest/utils';
-jest.mock('../../../../src/arbitrary/array');
-jest.mock('../../../../src/arbitrary/integer');
-import * as ArrayArbitraryMock from '../../../../src/arbitrary/array';
-import * as IntegerMock from '../../../../src/arbitrary/integer';
+jest.mock('../../../src/arbitrary/array');
+jest.mock('../../../src/arbitrary/integer');
+import * as ArrayArbitraryMock from '../../../src/arbitrary/array';
+import * as IntegerMock from '../../../src/arbitrary/integer';
 
 const validArrayConstraintsArb = () =>
   fc.record({ minLength: fc.nat(), maxLength: fc.nat() }, { withDeletedKeys: true }).map((ct) => {