Repository: dubzzz/fast-check
Pull request #2498 (2021-11-19 20:15:34)

💥 Change the API of a property
In other words, the API of a property has been changed to the one we defined in INextRawProperty.

<!-- 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
- [ ] ⚡️ Improve performance
- [x] _Other(s):_ breaking changes
<!-- Don't forget to add the gitmoji icon in the name of the PR -->
<!-- See: https://gitmoji.dev/                                  -->

<!-- Fixing bugs, adding features... 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/2498/builds/190115) or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 58dd2ae03dcc3ef29f9eff84cb0f9b891cb1277e:

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

codecov[bot]: # [Codecov](https://codecov.io/gh/dubzzz/fast-check/pull/2498?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN) Report
> Merging [#2498](https://codecov.io/gh/dubzzz/fast-check/pull/2498?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN) (d0da059) into [next-2_19_0](https://codecov.io/gh/dubzzz/fast-check/commit/367124c419f077aafef8e2cbff4e8893b1c2f085?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN) (367124c) will **increase** coverage by `0.01%`.
> The diff coverage is `90.90%`.

[![Impacted file tree graph](https://codecov.io/gh/dubzzz/fast-check/pull/2498/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/2498?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN)

```diff
@@               Coverage Diff               @@
##           next-2_19_0    #2498      +/-   ##
===============================================
+ Coverage        96.02%   96.04%   +0.01%     
===============================================
  Files              197      194       -3     
  Lines             4578     4498      -80     
  Branches           900      895       -5     
===============================================
- Hits              4396     4320      -76     
+ Misses             178      174       -4     
  Partials             4        4              
```

| Flag | Coverage Δ | |
|---|---|---|
| unit-tests | `96.04% <90.90%> (+0.01%)` | :arrow_up: |

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/2498?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN) | Coverage Δ | |
|---|---|---|
| [src/check/property/IRawProperty.ts](https://codecov.io/gh/dubzzz/fast-check/pull/2498/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#diff-c3JjL2NoZWNrL3Byb3BlcnR5L0lSYXdQcm9wZXJ0eS50cw==) | `100.00% <ø> (ø)` | |
| [src/check/runner/Runner.ts](https://codecov.io/gh/dubzzz/fast-check/pull/2498/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#diff-c3JjL2NoZWNrL3J1bm5lci9SdW5uZXIudHM=) | `100.00% <ø> (ø)` | |
| [src/check/runner/Sampler.ts](https://codecov.io/gh/dubzzz/fast-check/pull/2498/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#diff-c3JjL2NoZWNrL3J1bm5lci9TYW1wbGVyLnRz) | `93.47% <0.00%> (-0.14%)` | :arrow_down: |
| [src/check/property/UnbiasedProperty.ts](https://codecov.io/gh/dubzzz/fast-check/pull/2498/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#diff-c3JjL2NoZWNrL3Byb3BlcnR5L1VuYmlhc2VkUHJvcGVydHkudHM=) | `40.00% <66.66%> (ø)` | |
| [src/check/property/AsyncProperty.generic.ts](https://codecov.io/gh/dubzzz/fast-check/pull/2498/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#diff-c3JjL2NoZWNrL3Byb3BlcnR5L0FzeW5jUHJvcGVydHkuZ2VuZXJpYy50cw==) | `93.18% <100.00%> (ø)` | |
| [src/check/property/AsyncProperty.ts](https://codecov.io/gh/dubzzz/fast-check/pull/2498/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#diff-c3JjL2NoZWNrL3Byb3BlcnR5L0FzeW5jUHJvcGVydHkudHM=) | `92.30% <100.00%> (-0.55%)` | :arrow_down: |
| [src/check/property/IgnoreEqualValuesProperty.ts](https://codecov.io/gh/dubzzz/fast-check/pull/2498/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#diff-c3JjL2NoZWNrL3Byb3BlcnR5L0lnbm9yZUVxdWFsVmFsdWVzUHJvcGVydHkudHM=) | `78.57% <100.00%> (ø)` | |
| [src/check/property/Property.generic.ts](https://codecov.io/gh/dubzzz/fast-check/pull/2498/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#diff-c3JjL2NoZWNrL3Byb3BlcnR5L1Byb3BlcnR5LmdlbmVyaWMudHM=) | `93.47% <100.00%> (ø)` | |
| [src/check/property/Property.ts](https://codecov.io/gh/dubzzz/fast-check/pull/2498/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#diff-c3JjL2NoZWNrL3Byb3BlcnR5L1Byb3BlcnR5LnRz) | `92.30% <100.00%> (-0.55%)` | :arrow_down: |
| [src/check/property/SkipAfterProperty.ts](https://codecov.io/gh/dubzzz/fast-check/pull/2498/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN#diff-c3JjL2NoZWNrL3Byb3BlcnR5L1NraXBBZnRlclByb3BlcnR5LnRz) | `94.73% <100.00%> (ø)` | |
| ... and [3 more](https://codecov.io/gh/dubzzz/fast-check/pull/2498/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/2498?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/2498?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Nicolas+DUBIEN). Last update [367124c...d0da059](https://codecov.io/gh/dubzzz/fast-check/pull/2498?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/check/property/AsyncProperty.generic.ts b/src/check/property/AsyncProperty.generic.ts
index 3cb5de2e..04e167e1 100644
--- a/src/check/property/AsyncProperty.generic.ts
+++ b/src/check/property/AsyncProperty.generic.ts
@@ -3,7 +3,6 @@ import { Arbitrary } from '../arbitrary/definition/Arbitrary';
 import { PreconditionFailure } from '../precondition/PreconditionFailure';
 import { IRawProperty, runIdToFrequency } from './IRawProperty';
 import { readConfigureGlobal, GlobalAsyncPropertyHookFunction } from '../runner/configuration/GlobalParameters';
-import { INextRawProperty } from './INextRawProperty';
 import { NextValue } from '../arbitrary/definition/NextValue';
 import { Stream } from '../../stream/Stream';
 import { NextArbitrary } from '../arbitrary/definition/NextArbitrary';
@@ -52,15 +51,6 @@ export interface IAsyncPropertyWithHooks<Ts> extends IAsyncProperty<Ts> {
   afterEach(hookFunction: AsyncPropertyHookFunction): IAsyncPropertyWithHooks<Ts>;
 }
 
-/** @internal */
-interface INextAsyncProperty<Ts> extends INextRawProperty<Ts, true> {}
-
-/** @internal */
-interface INextAsyncPropertyWithHooks<Ts> extends INextAsyncProperty<Ts> {
-  beforeEach(hookFunction: AsyncPropertyHookFunction): INextAsyncPropertyWithHooks<Ts>;
-  afterEach(hookFunction: AsyncPropertyHookFunction): INextAsyncPropertyWithHooks<Ts>;
-}
-
 /**
  * Asynchronous property, see {@link IAsyncProperty}
  *
@@ -68,7 +58,7 @@ interface INextAsyncPropertyWithHooks<Ts> extends INextAsyncProperty<Ts> {
  *
  * @internal
  */
-export class AsyncProperty<Ts> implements INextAsyncPropertyWithHooks<Ts> {
+export class AsyncProperty<Ts> implements IAsyncPropertyWithHooks<Ts> {
   // Default hook is a no-op
   // eslint-disable-next-line @typescript-eslint/no-empty-function
   static dummyHook: GlobalAsyncPropertyHookFunction = () => {};
diff --git a/src/check/property/AsyncProperty.ts b/src/check/property/AsyncProperty.ts
index 2d5033de..93efc4c0 100644
--- a/src/check/property/AsyncProperty.ts
+++ b/src/check/property/AsyncProperty.ts
@@ -8,7 +8,6 @@ import {
 } from './AsyncProperty.generic';
 import { AlwaysShrinkableArbitrary } from '../../arbitrary/_internals/AlwaysShrinkableArbitrary';
 import { convertFromNext, convertToNext } from '../arbitrary/definition/Converters';
-import { convertFromNextAsyncPropertyWithHooks } from './ConvertersProperty';
 
 /**
  * Instantiate a new {@link fast-check#IAsyncProperty}
@@ -27,7 +26,7 @@ function asyncProperty<Ts extends [unknown, ...unknown[]]>(
   const mappedArbs = arbs.map((arb): typeof arb =>
     convertFromNext(new AlwaysShrinkableArbitrary(convertToNext(arb)))
   ) as typeof arbs;
-  return convertFromNextAsyncPropertyWithHooks(new AsyncProperty(tuple<Ts>(...mappedArbs), (t) => p(...t)));
+  return new AsyncProperty(tuple<Ts>(...mappedArbs), (t) => p(...t));
 }
 
 export { asyncProperty, IAsyncProperty, IAsyncPropertyWithHooks, AsyncPropertyHookFunction };
diff --git a/src/check/property/ConverterFromNextProperty.ts b/src/check/property/ConverterFromNextProperty.ts
deleted file mode 100644
index 3392a4a2..00000000
--- a/src/check/property/ConverterFromNextProperty.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-import { Random } from '../../random/generator/Random';
-import { NextValue } from '../arbitrary/definition/NextValue';
-import { Shrinkable } from '../arbitrary/definition/Shrinkable';
-import { PreconditionFailure } from '../precondition/PreconditionFailure';
-import { INextRawProperty } from './INextRawProperty';
-import { IRawProperty } from './IRawProperty';
-
-const identifier = '__ConverterFromNextProperty__';
-
-/** @internal */
-function fromNextValueToShrinkableFor<T>(property: INextRawProperty<T>) {
-  return function fromNextValueToShrinkable(v: NextValue<T>): Shrinkable<T, T> {
-    const shrinker = () => property.shrink(v).map(fromNextValueToShrinkable);
-    if (!v.hasToBeCloned) {
-      return new Shrinkable(v.value_, shrinker);
-    }
-    return new Shrinkable(v.value_, shrinker, () => v.value);
-  };
-}
-
-/** @internal */
-export class ConverterFromNextProperty<Ts, IsAsync extends boolean> implements IRawProperty<Ts, IsAsync> {
-  [identifier] = true;
-  static isConverterFromNext<Ts, IsAsync extends boolean>(
-    property: IRawProperty<Ts, IsAsync>
-  ): property is ConverterFromNextProperty<Ts, IsAsync> {
-    return identifier in property;
-  }
-
-  public toShrinkable: (v: NextValue<Ts>) => Shrinkable<Ts, Ts>;
-  constructor(readonly property: INextRawProperty<Ts, IsAsync>) {
-    this.toShrinkable = fromNextValueToShrinkableFor(property);
-  }
-
-  isAsync(): IsAsync {
-    return this.property.isAsync();
-  }
-
-  generate(mrng: Random, runId?: number): Shrinkable<Ts> {
-    const value = this.property.generate(mrng, runId);
-    return this.toShrinkable(value);
-  }
-
-  run(
-    v: Ts
-  ):
-    | (IsAsync extends true ? Promise<string | PreconditionFailure | null> : never)
-    | (IsAsync extends false ? string | PreconditionFailure | null : never) {
-    return this.property.run(v);
-  }
-}
diff --git a/src/check/property/ConverterToNextProperty.ts b/src/check/property/ConverterToNextProperty.ts
deleted file mode 100644
index c212ae04..00000000
--- a/src/check/property/ConverterToNextProperty.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-import { Random } from '../../random/generator/Random';
-import { Stream } from '../../stream/Stream';
-import { fromShrinkableToNextValue } from '../arbitrary/definition/ConverterToNext';
-import { NextValue } from '../arbitrary/definition/NextValue';
-import { Shrinkable } from '../arbitrary/definition/Shrinkable';
-import { PreconditionFailure } from '../precondition/PreconditionFailure';
-import { INextRawProperty } from './INextRawProperty';
-import { IRawProperty } from './IRawProperty';
-
-const identifier = '__ConverterToNextProperty__';
-
-/** @internal */
-export class ConverterToNextProperty<Ts, IsAsync extends boolean> implements INextRawProperty<Ts, IsAsync> {
-  [identifier] = true;
-  static isConverterToNext<Ts, IsAsync extends boolean>(
-    property: INextRawProperty<Ts, IsAsync>
-  ): property is ConverterToNextProperty<Ts, IsAsync> {
-    return identifier in property;
-  }
-
-  constructor(readonly property: IRawProperty<Ts, IsAsync>) {}
-
-  isAsync(): IsAsync {
-    return this.property.isAsync();
-  }
-
-  generate(mrng: Random, runId?: number): NextValue<Ts> {
-    const shrinkable = this.property.generate(mrng, runId);
-    return fromShrinkableToNextValue(shrinkable);
-  }
-
-  shrink(value: NextValue<Ts>): Stream<NextValue<Ts>> {
-    if (this.isSafeContext(value.context)) {
-      return value.context.shrink().map(fromShrinkableToNextValue);
-    }
-    return Stream.nil();
-  }
-  private isSafeContext(context: unknown): context is Shrinkable<Ts> {
-    return (
-      context != null && typeof context === 'object' && 'value' in (context as any) && 'shrink' in (context as any)
-    );
-  }
-
-  run(
-    v: Ts
-  ):
-    | (IsAsync extends true ? Promise<string | PreconditionFailure | null> : never)
-    | (IsAsync extends false ? string | PreconditionFailure | null : never) {
-    return this.property.run(v);
-  }
-}
diff --git a/src/check/property/ConvertersProperty.ts b/src/check/property/ConvertersProperty.ts
deleted file mode 100644
index 241478ee..00000000
--- a/src/check/property/ConvertersProperty.ts
+++ /dev/null
@@ -1,65 +0,0 @@
-import {
-  AsyncProperty,
-  AsyncPropertyHookFunction,
-  IAsyncProperty,
-  IAsyncPropertyWithHooks,
-} from './AsyncProperty.generic';
-import { ConverterFromNextProperty } from './ConverterFromNextProperty';
-import { ConverterToNextProperty } from './ConverterToNextProperty';
-import { INextRawProperty } from './INextRawProperty';
-import { IRawProperty } from './IRawProperty';
-import { IProperty, IPropertyWithHooks, Property, PropertyHookFunction } from './Property.generic';
-
-/** @internal */
-export function convertFromNextProperty<Ts, IsAsync extends boolean>(
-  property: INextRawProperty<Ts, IsAsync>
-): IRawProperty<Ts, IsAsync> {
-  if (ConverterToNextProperty.isConverterToNext(property)) {
-    return property.property;
-  }
-  return new ConverterFromNextProperty(property);
-}
-
-/** @internal */
-export function convertToNextProperty<Ts, IsAsync extends boolean>(
-  property: IRawProperty<Ts, IsAsync>
-): INextRawProperty<Ts, IsAsync> {
-  if (ConverterFromNextProperty.isConverterFromNext(property)) {
-    return property.property;
-  }
-  return new ConverterToNextProperty(property);
-}
-
-/** @internal */
-export function convertFromNextPropertyWithHooks<Ts>(property: Property<Ts>): IProperty<Ts> & IPropertyWithHooks<Ts> {
-  const oldProperty = convertFromNextProperty(property) as IProperty<Ts> & IPropertyWithHooks<Ts>;
-  const hooks = {
-    beforeEach(hookFunction: PropertyHookFunction): IPropertyWithHooks<Ts> {
-      property.beforeEach(hookFunction);
-      return oldProperty;
-    },
-    afterEach(hookFunction: PropertyHookFunction): IPropertyWithHooks<Ts> {
-      property.afterEach(hookFunction);
-      return oldProperty;
-    },
-  };
-  return Object.assign(oldProperty, hooks);
-}
-
-/** @internal */
-export function convertFromNextAsyncPropertyWithHooks<Ts>(
-  property: AsyncProperty<Ts>
-): IAsyncProperty<Ts> & IAsyncPropertyWithHooks<Ts> {
-  const oldProperty = convertFromNextProperty(property) as IAsyncProperty<Ts> & IAsyncPropertyWithHooks<Ts>;
-  const hooks = {
-    beforeEach(hookFunction: AsyncPropertyHookFunction): IAsyncPropertyWithHooks<Ts> {
-      property.beforeEach(hookFunction);
-      return oldProperty;
-    },
-    afterEach(hookFunction: AsyncPropertyHookFunction): IAsyncPropertyWithHooks<Ts> {
-      property.afterEach(hookFunction);
-      return oldProperty;
-    },
-  };
-  return Object.assign(oldProperty, hooks);
-}
diff --git a/src/check/property/INextRawProperty.ts b/src/check/property/INextRawProperty.ts
deleted file mode 100644
index 41820d94..00000000
--- a/src/check/property/INextRawProperty.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-import { Random } from '../../random/generator/Random';
-import { Stream } from '../../stream/Stream';
-import { NextValue } from '../arbitrary/definition/NextValue';
-import { PreconditionFailure } from '../precondition/PreconditionFailure';
-
-/**
- * Property
- *
- * A property is the combination of:
- * - Arbitraries: how to generate the inputs for the algorithm
- * - Predicate: how to confirm the algorithm succeeded?
- *
- * @remarks Since 2.19.0
- * @internal
- */
-export interface INextRawProperty<Ts, IsAsync extends boolean = boolean> {
-  /**
-   * Is the property asynchronous?
-   *
-   * true in case of asynchronous property, false otherwise
-   * @remarks Since 0.0.7
-   */
-  isAsync(): IsAsync;
-
-  /**
-   * Generate values of type Ts
-   *
-   * @param mrng - Random number generator
-   * @param runId - Id of the generation, starting at 0 - if set the generation might be biased
-   *
-   * @remarks Since 0.0.7
-   */
-  generate(mrng: Random, runId?: number): NextValue<Ts>;
-
-  /**
-   * Shrink value of type Ts
-   *
-   * @param value - The value to be shrunk, it can be context-less
-   *
-   * @remarks Since 2.19.0
-   */
-  shrink(value: NextValue<Ts>): Stream<NextValue<Ts>>;
-
-  /**
-   * Check the predicate for v
-   * @param v - Value of which we want to check the predicate
-   * @remarks Since 0.0.7
-   */
-  run(
-    v: Ts
-  ):
-    | (IsAsync extends true ? Promise<PreconditionFailure | string | null> : never)
-    | (IsAsync extends false ? PreconditionFailure | string | null : never);
-}
diff --git a/src/check/property/IRawProperty.ts b/src/check/property/IRawProperty.ts
index fbb5d873..6d8f145f 100644
--- a/src/check/property/IRawProperty.ts
+++ b/src/check/property/IRawProperty.ts
@@ -1,5 +1,6 @@
 import { Random } from '../../random/generator/Random';
-import { Shrinkable } from '../arbitrary/definition/Shrinkable';
+import { Stream } from '../../stream/Stream';
+import { NextValue } from '../arbitrary/definition/NextValue';
 import { PreconditionFailure } from '../precondition/PreconditionFailure';
 
 /**
@@ -20,15 +21,26 @@ export interface IRawProperty<Ts, IsAsync extends boolean = boolean> {
    * @remarks Since 0.0.7
    */
   isAsync(): IsAsync;
+
   /**
    * Generate values of type Ts
    *
    * @param mrng - Random number generator
    * @param runId - Id of the generation, starting at 0 - if set the generation might be biased
    *
-   * @remarks Since 0.0.7
+   * @remarks Since 0.0.7 (return type changed in 3.0.0)
+   */
+  generate(mrng: Random, runId?: number): NextValue<Ts>;
+
+  /**
+   * Shrink value of type Ts
+   *
+   * @param value - The value to be shrunk, it can be context-less
+   *
+   * @remarks Since 3.0.0
    */
-  generate(mrng: Random, runId?: number): Shrinkable<Ts>;
+  shrink(value: NextValue<Ts>): Stream<NextValue<Ts>>;
+
   /**
    * Check the predicate for v
    * @param v - Value of which we want to check the predicate
diff --git a/src/check/property/IgnoreEqualValuesProperty.ts b/src/check/property/IgnoreEqualValuesProperty.ts
index d175a803..bc24a1d7 100644
--- a/src/check/property/IgnoreEqualValuesProperty.ts
+++ b/src/check/property/IgnoreEqualValuesProperty.ts
@@ -1,4 +1,4 @@
-import { INextRawProperty } from './INextRawProperty';
+import { IRawProperty } from './IRawProperty';
 import { Random } from '../../random/generator/Random';
 import { stringify } from '../../utils/stringify';
 import { PreconditionFailure } from '../precondition/PreconditionFailure';
@@ -7,25 +7,23 @@ import { Stream } from '../../stream/Stream';
 
 /** @internal */
 function fromSyncCached<Ts>(
-  cachedValue: ReturnType<INextRawProperty<Ts, false>['run']>
-): ReturnType<INextRawProperty<Ts, false>['run']> {
+  cachedValue: ReturnType<IRawProperty<Ts, false>['run']>
+): ReturnType<IRawProperty<Ts, false>['run']> {
   return cachedValue === null ? new PreconditionFailure() : cachedValue;
 }
 
 /** @internal */
 function fromCached<Ts>(
-  cachedValue: ReturnType<INextRawProperty<Ts, false>['run']>,
+  cachedValue: ReturnType<IRawProperty<Ts, false>['run']>,
   isAsync: false
-): ReturnType<INextRawProperty<Ts, false>['run']>;
+): ReturnType<IRawProperty<Ts, false>['run']>;
 /** @internal */
 function fromCached<Ts>(
-  cachedValue: ReturnType<INextRawProperty<Ts, true>['run']>,
+  cachedValue: ReturnType<IRawProperty<Ts, true>['run']>,
   isAsync: true
-): ReturnType<INextRawProperty<Ts, true>['run']>;
+): ReturnType<IRawProperty<Ts, true>['run']>;
 function fromCached<Ts>(
-  ...data:
-    | [ReturnType<INextRawProperty<Ts, true>['run']>, true]
-    | [ReturnType<INextRawProperty<Ts, false>['run']>, false]
+  ...data: [ReturnType<IRawProperty<Ts, true>['run']>, true] | [ReturnType<IRawProperty<Ts, false>['run']>, false]
 ) {
   if (data[1]) return data[0].then(fromSyncCached);
   return fromSyncCached(data[0]);
@@ -33,17 +31,17 @@ function fromCached<Ts>(
 
 /** @internal */
 function fromCachedUnsafe<Ts, IsAsync extends boolean>(
-  cachedValue: ReturnType<INextRawProperty<Ts, IsAsync>['run']>,
+  cachedValue: ReturnType<IRawProperty<Ts, IsAsync>['run']>,
   isAsync: IsAsync
-): ReturnType<INextRawProperty<Ts, IsAsync>['run']> {
+): ReturnType<IRawProperty<Ts, IsAsync>['run']> {
   return fromCached(cachedValue as any, isAsync as any) as any;
 }
 
 /** @internal */
-export class IgnoreEqualValuesProperty<Ts, IsAsync extends boolean> implements INextRawProperty<Ts, IsAsync> {
-  private coveredCases: Map<string, ReturnType<INextRawProperty<Ts, IsAsync>['run']>> = new Map();
+export class IgnoreEqualValuesProperty<Ts, IsAsync extends boolean> implements IRawProperty<Ts, IsAsync> {
+  private coveredCases: Map<string, ReturnType<IRawProperty<Ts, IsAsync>['run']>> = new Map();
 
-  constructor(readonly property: INextRawProperty<Ts, IsAsync>, readonly skipRuns: boolean) {}
+  constructor(readonly property: IRawProperty<Ts, IsAsync>, readonly skipRuns: boolean) {}
 
   isAsync(): IsAsync {
     return this.property.isAsync();
@@ -57,10 +55,10 @@ export class IgnoreEqualValuesProperty<Ts, IsAsync extends boolean> implements I
     return this.property.shrink(value);
   }
 
-  run(v: Ts): ReturnType<INextRawProperty<Ts, IsAsync>['run']> {
+  run(v: Ts): ReturnType<IRawProperty<Ts, IsAsync>['run']> {
     const stringifiedValue = stringify(v);
     if (this.coveredCases.has(stringifiedValue)) {
-      const lastOutput = this.coveredCases.get(stringifiedValue) as ReturnType<INextRawProperty<Ts, IsAsync>['run']>;
+      const lastOutput = this.coveredCases.get(stringifiedValue) as ReturnType<IRawProperty<Ts, IsAsync>['run']>;
       if (!this.skipRuns) {
         return lastOutput;
       }
diff --git a/src/check/property/Property.generic.ts b/src/check/property/Property.generic.ts
index 7b186267..d76d5674 100644
--- a/src/check/property/Property.generic.ts
+++ b/src/check/property/Property.generic.ts
@@ -3,7 +3,6 @@ import { Arbitrary } from '../arbitrary/definition/Arbitrary';
 import { PreconditionFailure } from '../precondition/PreconditionFailure';
 import { IRawProperty, runIdToFrequency } from './IRawProperty';
 import { readConfigureGlobal, GlobalPropertyHookFunction } from '../runner/configuration/GlobalParameters';
-import { INextRawProperty } from './INextRawProperty';
 import { NextValue } from '../arbitrary/definition/NextValue';
 import { NextArbitrary } from '../arbitrary/definition/NextArbitrary';
 import { convertToNext } from '../arbitrary/definition/Converters';
@@ -67,23 +66,6 @@ export interface IPropertyWithHooks<Ts> extends IProperty<Ts> {
   afterEach(hookFunction: PropertyHookFunction): IPropertyWithHooks<Ts>;
 }
 
-/** @internal */
-interface INextProperty<Ts> extends INextRawProperty<Ts, false> {}
-
-/** @internal */
-interface INextPropertyWithHooks<Ts> extends INextProperty<Ts> {
-  beforeEach(
-    invalidHookFunction: (hookFunction: GlobalPropertyHookFunction) => Promise<unknown>
-  ): 'beforeEach expects a synchronous function but was given a function returning a Promise';
-
-  beforeEach(hookFunction: PropertyHookFunction): INextPropertyWithHooks<Ts>;
-
-  afterEach(
-    invalidHookFunction: (hookFunction: GlobalPropertyHookFunction) => Promise<unknown>
-  ): 'afterEach expects a synchronous function but was given a function returning a Promise';
-  afterEach(hookFunction: PropertyHookFunction): INextPropertyWithHooks<Ts>;
-}
-
 /**
  * Property, see {@link IProperty}
  *
@@ -91,7 +73,7 @@ interface INextPropertyWithHooks<Ts> extends INextProperty<Ts> {
  *
  * @internal
  */
-export class Property<Ts> implements INextProperty<Ts>, INextPropertyWithHooks<Ts> {
+export class Property<Ts> implements IProperty<Ts>, IPropertyWithHooks<Ts> {
   // Default hook is a no-op
   // eslint-disable-next-line @typescript-eslint/no-empty-function
   static dummyHook: GlobalPropertyHookFunction = () => {};
diff --git a/src/check/property/Property.ts b/src/check/property/Property.ts
index fddbf298..701cee8a 100644
--- a/src/check/property/Property.ts
+++ b/src/check/property/Property.ts
@@ -3,7 +3,6 @@ import { tuple } from '../../arbitrary/tuple';
 import { Property, IProperty, IPropertyWithHooks, PropertyHookFunction } from './Property.generic';
 import { AlwaysShrinkableArbitrary } from '../../arbitrary/_internals/AlwaysShrinkableArbitrary';
 import { convertFromNext, convertToNext } from '../arbitrary/definition/Converters';
-import { convertFromNextPropertyWithHooks } from './ConvertersProperty';
 
 /**
  * Instantiate a new {@link fast-check#IProperty}
@@ -22,7 +21,7 @@ function property<Ts extends [unknown, ...unknown[]]>(
   const mappedArbs = arbs.map((arb): typeof arb =>
     convertFromNext(new AlwaysShrinkableArbitrary(convertToNext(arb)))
   ) as typeof arbs;
-  return convertFromNextPropertyWithHooks(new Property(tuple<Ts>(...mappedArbs), (t) => p(...t)));
+  return new Property(tuple<Ts>(...mappedArbs), (t) => p(...t));
 }
 
 export { property, IProperty, IPropertyWithHooks, PropertyHookFunction };
diff --git a/src/check/property/SkipAfterProperty.ts b/src/check/property/SkipAfterProperty.ts
index 60178bb3..c56649ce 100644
--- a/src/check/property/SkipAfterProperty.ts
+++ b/src/check/property/SkipAfterProperty.ts
@@ -2,13 +2,13 @@ import { Random } from '../../random/generator/Random';
 import { Stream } from '../../stream/Stream';
 import { NextValue } from '../arbitrary/definition/NextValue';
 import { PreconditionFailure } from '../precondition/PreconditionFailure';
-import { INextRawProperty } from './INextRawProperty';
+import { IRawProperty } from './IRawProperty';
 
 /** @internal */
-export class SkipAfterProperty<Ts, IsAsync extends boolean> implements INextRawProperty<Ts, IsAsync> {
+export class SkipAfterProperty<Ts, IsAsync extends boolean> implements IRawProperty<Ts, IsAsync> {
   private skipAfterTime: number;
   constructor(
-    readonly property: INextRawProperty<Ts, IsAsync>,
+    readonly property: IRawProperty<Ts, IsAsync>,
     readonly getTime: () => number,
     timeLimit: number,
     readonly interruptExecution: boolean
@@ -28,7 +28,7 @@ export class SkipAfterProperty<Ts, IsAsync extends boolean> implements INextRawP
     return this.property.shrink(value);
   }
 
-  run(v: Ts): ReturnType<INextRawProperty<Ts, IsAsync>['run']> {
+  run(v: Ts): ReturnType<IRawProperty<Ts, IsAsync>['run']> {
     if (this.getTime() >= this.skipAfterTime) {
       const preconditionFailure = new PreconditionFailure(this.interruptExecution);
       if (this.isAsync()) {
diff --git a/src/check/property/TimeoutProperty.ts b/src/check/property/TimeoutProperty.ts
index d131edd7..3e0a7d4d 100644
--- a/src/check/property/TimeoutProperty.ts
+++ b/src/check/property/TimeoutProperty.ts
@@ -2,7 +2,7 @@ import { Random } from '../../random/generator/Random';
 import { Stream } from '../../stream/Stream';
 import { NextValue } from '../arbitrary/definition/NextValue';
 import { PreconditionFailure } from '../precondition/PreconditionFailure';
-import { INextRawProperty } from './INextRawProperty';
+import { IRawProperty } from './IRawProperty';
 
 /** @internal */
 const timeoutAfter = (timeMs: number) => {
@@ -21,8 +21,8 @@ const timeoutAfter = (timeMs: number) => {
 };
 
 /** @internal */
-export class TimeoutProperty<Ts> implements INextRawProperty<Ts, true> {
-  constructor(readonly property: INextRawProperty<Ts>, readonly timeMs: number) {}
+export class TimeoutProperty<Ts> implements IRawProperty<Ts, true> {
+  constructor(readonly property: IRawProperty<Ts>, readonly timeMs: number) {}
 
   isAsync(): true {
     return true;
diff --git a/src/check/property/UnbiasedProperty.ts b/src/check/property/UnbiasedProperty.ts
index 5e838727..f69d1867 100644
--- a/src/check/property/UnbiasedProperty.ts
+++ b/src/check/property/UnbiasedProperty.ts
@@ -1,11 +1,11 @@
 import { Random } from '../../random/generator/Random';
 import { Stream } from '../../stream/Stream';
 import { NextValue } from '../arbitrary/definition/NextValue';
-import { INextRawProperty } from './INextRawProperty';
+import { IRawProperty } from './IRawProperty';
 
 /** @internal */
-export class UnbiasedProperty<Ts, IsAsync extends boolean> implements INextRawProperty<Ts, IsAsync> {
-  constructor(readonly property: INextRawProperty<Ts, IsAsync>) {}
+export class UnbiasedProperty<Ts, IsAsync extends boolean> implements IRawProperty<Ts, IsAsync> {
+  constructor(readonly property: IRawProperty<Ts, IsAsync>) {}
 
   isAsync(): IsAsync {
     return this.property.isAsync();
@@ -19,7 +19,7 @@ export class UnbiasedProperty<Ts, IsAsync extends boolean> implements INextRawPr
     return this.property.shrink(value);
   }
 
-  run(v: Ts): ReturnType<INextRawProperty<Ts, IsAsync>['run']> {
+  run(v: Ts): ReturnType<IRawProperty<Ts, IsAsync>['run']> {
     return this.property.run(v);
   }
 }
diff --git a/src/check/runner/DecorateProperty.ts b/src/check/runner/DecorateProperty.ts
index 8d96928a..3feb6263 100644
--- a/src/check/runner/DecorateProperty.ts
+++ b/src/check/runner/DecorateProperty.ts
@@ -4,8 +4,6 @@ import { TimeoutProperty } from '../property/TimeoutProperty';
 import { UnbiasedProperty } from '../property/UnbiasedProperty';
 import { QualifiedParameters } from './configuration/QualifiedParameters';
 import { IgnoreEqualValuesProperty } from '../property/IgnoreEqualValuesProperty';
-import { convertToNextProperty } from '../property/ConvertersProperty';
-import { INextRawProperty } from '../property/INextRawProperty';
 
 /** @internal */
 type MinimalQualifiedParameters<Ts> = Pick<
@@ -17,8 +15,8 @@ type MinimalQualifiedParameters<Ts> = Pick<
 export function decorateProperty<Ts>(
   rawProperty: IRawProperty<Ts>,
   qParams: MinimalQualifiedParameters<Ts>
-): INextRawProperty<Ts> {
-  let prop = convertToNextProperty(rawProperty);
+): IRawProperty<Ts> {
+  let prop = rawProperty;
   if (rawProperty.isAsync() && qParams.timeout != null) {
     prop = new TimeoutProperty(prop, qParams.timeout);
   }
diff --git a/src/check/runner/Runner.ts b/src/check/runner/Runner.ts
index abe97b38..b6c7eb7d 100644
--- a/src/check/runner/Runner.ts
+++ b/src/check/runner/Runner.ts
@@ -15,12 +15,11 @@ import { pathWalk } from './utils/PathWalker';
 import { asyncReportRunDetails, reportRunDetails } from './utils/RunDetailsFormatter';
 import { IAsyncProperty } from '../property/AsyncProperty';
 import { IProperty } from '../property/Property';
-import { INextRawProperty } from '../property/INextRawProperty';
 import { NextValue } from '../arbitrary/definition/NextValue';
 
 /** @internal */
 function runIt<Ts>(
-  property: INextRawProperty<Ts>,
+  property: IRawProperty<Ts>,
   shrink: (value: NextValue<Ts>) => IterableIterator<NextValue<Ts>>,
   sourceValues: SourceValuesIterator<NextValue<Ts>>,
   verbose: VerbosityLevel,
@@ -36,7 +35,7 @@ function runIt<Ts>(
 
 /** @internal */
 async function asyncRunIt<Ts>(
-  property: INextRawProperty<Ts>,
+  property: IRawProperty<Ts>,
   shrink: (value: NextValue<Ts>) => IterableIterator<NextValue<Ts>>,
   sourceValues: SourceValuesIterator<NextValue<Ts>>,
   verbose: VerbosityLevel,
diff --git a/src/check/runner/Sampler.ts b/src/check/runner/Sampler.ts
index 5a9ecb10..7b9ac61a 100644
--- a/src/check/runner/Sampler.ts
+++ b/src/check/runner/Sampler.ts
@@ -1,8 +1,6 @@
 import { Stream, stream } from '../../stream/Stream';
 import { Arbitrary } from '../arbitrary/definition/Arbitrary';
 import { NextValue } from '../arbitrary/definition/NextValue';
-import { convertToNextProperty } from '../property/ConvertersProperty';
-import { INextRawProperty } from '../property/INextRawProperty';
 import { IRawProperty } from '../property/IRawProperty';
 import { Property } from '../property/Property.generic';
 import { UnbiasedProperty } from '../property/UnbiasedProperty';
@@ -16,10 +14,10 @@ import { pathWalk } from './utils/PathWalker';
 function toProperty<Ts>(
   generator: IRawProperty<Ts> | Arbitrary<Ts>,
   qParams: QualifiedParameters<Ts>
-): INextRawProperty<Ts> {
+): IRawProperty<Ts> {
   const prop = !Object.prototype.hasOwnProperty.call(generator, 'isAsync')
     ? new Property(generator as Arbitrary<Ts>, () => true)
-    : convertToNextProperty(generator as IRawProperty<Ts>);
+    : (generator as IRawProperty<Ts>);
   return qParams.unbiased === true ? new UnbiasedProperty(prop) : prop;
 }
 
diff --git a/src/check/runner/Tosser.ts b/src/check/runner/Tosser.ts
index 872adb38..cf8757cb 100644
--- a/src/check/runner/Tosser.ts
+++ b/src/check/runner/Tosser.ts
@@ -1,17 +1,17 @@
 import { RandomGenerator, skipN } from 'pure-rand';
 
 import { Random } from '../../random/generator/Random';
-import { INextRawProperty } from '../property/INextRawProperty';
+import { IRawProperty } from '../property/IRawProperty';
 import { NextValue } from '../arbitrary/definition/NextValue';
 
 /** @internal */
-function lazyGenerate<Ts>(generator: INextRawProperty<Ts>, rng: RandomGenerator, idx: number): () => NextValue<Ts> {
+function lazyGenerate<Ts>(generator: IRawProperty<Ts>, rng: RandomGenerator, idx: number): () => NextValue<Ts> {
   return () => generator.generate(new Random(rng), idx);
 }
 
 /** @internal */
 export function* toss<Ts>(
-  generator: INextRawProperty<Ts>,
+  generator: IRawProperty<Ts>,
   seed: number,
   random: (seed: number) => RandomGenerator,
   examples: Ts[]


Test patch:
diff --git a/test/unit/check/property/AsyncProperty.spec.ts b/test/unit/check/property/AsyncProperty.spec.ts
index 1e25f8ba..33a67c96 100644
--- a/test/unit/check/property/AsyncProperty.spec.ts
+++ b/test/unit/check/property/AsyncProperty.spec.ts
@@ -9,7 +9,6 @@ import * as stubArb from '../../stubs/arbitraries';
 import * as stubRng from '../../stubs/generators';
 import { NextValue } from '../../../../src/check/arbitrary/definition/NextValue';
 import { fakeNextArbitrary } from '../../arbitrary/__test-helpers__/NextArbitraryHelpers';
-import { convertToNextProperty } from '../../../../src/check/property/ConvertersProperty';
 import { convertFromNext } from '../../../../src/check/arbitrary/definition/Converters';
 import { Stream } from '../../../../src/stream/Stream';
 
@@ -279,7 +278,7 @@ describe('AsyncProperty', () => {
     const value = Symbol();
 
     // Act
-    const p = convertToNextProperty(asyncProperty(convertFromNext(arb), jest.fn()));
+    const p = asyncProperty(convertFromNext(arb), jest.fn());
     const shrinks = p.shrink(new NextValue([value], undefined)); // context=undefined in the case of user defined values
 
     // Assert
@@ -298,7 +297,7 @@ describe('AsyncProperty', () => {
     const value = Symbol();
 
     // Act
-    const p = convertToNextProperty(asyncProperty(convertFromNext(arb), jest.fn()));
+    const p = asyncProperty(convertFromNext(arb), jest.fn());
     const shrinks = p.shrink(new NextValue([value], undefined)); // context=undefined in the case of user defined values
 
     // Assert
diff --git a/test/unit/check/property/ConverterFromNextProperty.spec.ts b/test/unit/check/property/ConverterFromNextProperty.spec.ts
deleted file mode 100644
index afd6680b..00000000
--- a/test/unit/check/property/ConverterFromNextProperty.spec.ts
+++ /dev/null
@@ -1,123 +0,0 @@
-import { NextValue } from '../../../../src/check/arbitrary/definition/NextValue';
-import { Shrinkable } from '../../../../src/check/arbitrary/definition/Shrinkable';
-import { PreconditionFailure } from '../../../../src/check/precondition/PreconditionFailure';
-import { INextRawProperty } from '../../../../src/check/property/INextRawProperty';
-import { IRawProperty } from '../../../../src/check/property/IRawProperty';
-import { ConverterFromNextProperty } from '../../../../src/check/property/ConverterFromNextProperty';
-import { Random } from '../../../../src/random/generator/Random';
-import { Stream } from '../../../../src/stream/Stream';
-import { fakeRandom } from '../../arbitrary/__test-helpers__/RandomHelpers';
-
-describe('ConverterFromNextProperty', () => {
-  describe('isConverterFromNext', () => {
-    it('should detect its own instances', () => {
-      // Arrange
-      class MyNextProperty implements INextRawProperty<number, false> {
-        isAsync(): false {
-          throw new Error('Method not implemented.');
-        }
-        generate(_mrng: Random, _runId?: number): NextValue<number> {
-          throw new Error('Method not implemented.');
-        }
-        shrink(_value: NextValue<number>): Stream<NextValue<number>> {
-          throw new Error('Method not implemented.');
-        }
-        run(_v: number): string | PreconditionFailure {
-          throw new Error('Method not implemented.');
-        }
-      }
-      const originalInstance = new MyNextProperty();
-
-      // Act
-      const transformedInstance = new ConverterFromNextProperty(originalInstance);
-
-      // Assert
-      expect(ConverterFromNextProperty.isConverterFromNext(transformedInstance)).toBe(true);
-    });
-
-    it('should not consider instances of IRawProperty as its own instances', () => {
-      // Arrange
-      class MyProperty implements IRawProperty<number, false> {
-        isAsync(): false {
-          throw new Error('Method not implemented.');
-        }
-        generate(_mrng: Random, _runId?: number): Shrinkable<number, number> {
-          throw new Error('Method not implemented.');
-        }
-        run(_v: number): string | PreconditionFailure {
-          throw new Error('Method not implemented.');
-        }
-      }
-
-      // Act
-      const originalInstance = new MyProperty();
-
-      // Assert
-      expect(ConverterFromNextProperty.isConverterFromNext(originalInstance)).toBe(false);
-    });
-  });
-
-  describe('generate', () => {
-    it('should be able to use the underlying property to build values', () => {
-      // Arrange
-      const runId = 123;
-      const expectedValue = Symbol();
-      const isAsync = jest.fn();
-      const generate = jest.fn().mockReturnValueOnce(new NextValue(expectedValue, undefined));
-      const shrink = jest.fn();
-      const run = jest.fn();
-      class MyNextProperty implements INextRawProperty<number, false> {
-        isAsync = isAsync;
-        generate = generate;
-        shrink = shrink;
-        run = run;
-      }
-      const originalInstance = new MyNextProperty();
-      const { instance: mrng } = fakeRandom();
-
-      // Act
-      const transformedInstance = new ConverterFromNextProperty(originalInstance);
-      const out = transformedInstance.generate(mrng, runId);
-
-      // Assert
-      expect(out.value).toBe(expectedValue);
-      expect(generate).toHaveBeenCalledWith(mrng, runId);
-    });
-
-    it('should call shrink of the source property on shrink', () => {
-      // Arrange
-      const runId = 123;
-      const expectedValue = Symbol();
-      const expectedContext = Symbol();
-      const expectedNextValue = new NextValue(expectedValue, expectedContext);
-      const expectedShrink1 = Symbol();
-      const expectedShrink2 = Symbol();
-      const isAsync = jest.fn();
-      const generate = jest.fn().mockReturnValueOnce(expectedNextValue);
-      const shrink = jest
-        .fn()
-        .mockReturnValue(
-          Stream.of<Shrinkable<symbol>>(new Shrinkable(expectedShrink1), new Shrinkable(expectedShrink2))
-        );
-      const run = jest.fn();
-      class MyNextProperty implements INextRawProperty<number, false> {
-        isAsync = isAsync;
-        generate = generate;
-        shrink = shrink;
-        run = run;
-      }
-      const originalInstance = new MyNextProperty();
-      const { instance: mrng } = fakeRandom();
-
-      // Act
-      const transformedInstance = new ConverterFromNextProperty(originalInstance);
-      const shrinkable = transformedInstance.generate(mrng, runId);
-      expect(shrink).not.toHaveBeenCalled();
-      const shrinks = shrinkable.shrink();
-
-      // Assert
-      expect([...shrinks].map((v) => v.value)).toEqual([expectedShrink1, expectedShrink2]);
-      expect(shrink).toHaveBeenCalledWith(expectedNextValue);
-    });
-  });
-});
diff --git a/test/unit/check/property/ConverterToNextProperty.spec.ts b/test/unit/check/property/ConverterToNextProperty.spec.ts
deleted file mode 100644
index b12edef4..00000000
--- a/test/unit/check/property/ConverterToNextProperty.spec.ts
+++ /dev/null
@@ -1,150 +0,0 @@
-import { NextValue } from '../../../../src/check/arbitrary/definition/NextValue';
-import { Shrinkable } from '../../../../src/check/arbitrary/definition/Shrinkable';
-import { PreconditionFailure } from '../../../../src/check/precondition/PreconditionFailure';
-import { INextRawProperty } from '../../../../src/check/property/INextRawProperty';
-import { IRawProperty } from '../../../../src/check/property/IRawProperty';
-import { ConverterToNextProperty } from '../../../../src/check/property/ConverterToNextProperty';
-import { Random } from '../../../../src/random/generator/Random';
-import { Stream } from '../../../../src/stream/Stream';
-import { fakeRandom } from '../../arbitrary/__test-helpers__/RandomHelpers';
-
-describe('ConverterToNextProperty', () => {
-  describe('isConverterToNext', () => {
-    it('should detect its own instances', () => {
-      // Arrange
-      class MyProperty implements IRawProperty<number, false> {
-        isAsync(): false {
-          throw new Error('Method not implemented.');
-        }
-        generate(_mrng: Random, _runId?: number): Shrinkable<number, number> {
-          throw new Error('Method not implemented.');
-        }
-        run(_v: number): string | PreconditionFailure {
-          throw new Error('Method not implemented.');
-        }
-      }
-      const originalInstance = new MyProperty();
-
-      // Act
-      const transformedInstance = new ConverterToNextProperty(originalInstance);
-
-      // Assert
-      expect(ConverterToNextProperty.isConverterToNext(transformedInstance)).toBe(true);
-    });
-
-    it('should not consider instances of INextRawProperty as its own instances', () => {
-      // Arrange
-      class MyNextProperty implements INextRawProperty<number, false> {
-        isAsync(): false {
-          throw new Error('Method not implemented.');
-        }
-        generate(_mrng: Random, _runId?: number): NextValue<number> {
-          throw new Error('Method not implemented.');
-        }
-        shrink(_value: NextValue<number>): Stream<NextValue<number>> {
-          throw new Error('Method not implemented.');
-        }
-        run(_v: number): string | PreconditionFailure {
-          throw new Error('Method not implemented.');
-        }
-      }
-
-      // Act
-      const originalInstance = new MyNextProperty();
-
-      // Assert
-      expect(ConverterToNextProperty.isConverterToNext(originalInstance)).toBe(false);
-    });
-  });
-
-  describe('generate', () => {
-    it('should be able to use the underlying property to build values', () => {
-      // Arrange
-      const runId = 123;
-      const expectedValue = Symbol();
-      const isAsync = jest.fn();
-      const generate = jest.fn().mockReturnValueOnce(new Shrinkable(expectedValue));
-      const run = jest.fn();
-      class MyProperty implements IRawProperty<number, false> {
-        isAsync = isAsync;
-        generate = generate;
-        run = run;
-      }
-      const originalInstance = new MyProperty();
-      const { instance: mrng } = fakeRandom();
-
-      // Act
-      const transformedInstance = new ConverterToNextProperty(originalInstance);
-      const out = transformedInstance.generate(mrng, runId);
-
-      // Assert
-      expect(out.value).toBe(expectedValue);
-      expect(generate).toHaveBeenCalledWith(mrng, runId);
-    });
-  });
-
-  describe('shrink', () => {
-    it('should be able to shrink values produced by generate', () => {
-      // Arrange
-      const runId = 123;
-      const expectedValue = Symbol();
-      const expectedShrink1 = Symbol();
-      const expectedShrink2 = Symbol();
-      const shrinkable = new Shrinkable<symbol>(expectedValue, () =>
-        Stream.of<Shrinkable<symbol>>(new Shrinkable(expectedShrink1), new Shrinkable(expectedShrink2))
-      );
-      const isAsync = jest.fn();
-      const generate = jest.fn().mockReturnValueOnce(shrinkable);
-      const run = jest.fn();
-      class MyProperty implements IRawProperty<number, false> {
-        isAsync = isAsync;
-        generate = generate;
-        run = run;
-      }
-      const originalInstance = new MyProperty();
-      const { instance: mrng } = fakeRandom();
-
-      // Act
-      const transformedInstance = new ConverterToNextProperty(originalInstance);
-      const value = transformedInstance.generate(mrng, runId);
-      const shrinks = transformedInstance.shrink(value);
-
-      // Assert
-      expect([...shrinks].map((v) => v.value)).toEqual([expectedShrink1, expectedShrink2]);
-    });
-
-    it('should be able to shrink values produced by shrink', () => {
-      // Arrange
-      const runId = 123;
-      const expectedValue = Symbol();
-      const expectedShrink1 = Symbol();
-      const expectedShrink2 = Symbol();
-      const expectedShrink21 = Symbol();
-      const shrinkable = new Shrinkable<symbol>(expectedValue, () =>
-        Stream.of<Shrinkable<symbol>>(
-          new Shrinkable(expectedShrink1),
-          new Shrinkable<symbol>(expectedShrink2, () => Stream.of<Shrinkable<symbol>>(new Shrinkable(expectedShrink21)))
-        )
-      );
-      const isAsync = jest.fn();
-      const generate = jest.fn().mockReturnValueOnce(shrinkable);
-      const run = jest.fn();
-      class MyProperty implements IRawProperty<number, false> {
-        isAsync = isAsync;
-        generate = generate;
-        run = run;
-      }
-      const originalInstance = new MyProperty();
-      const { instance: mrng } = fakeRandom();
-
-      // Act
-      const transformedInstance = new ConverterToNextProperty(originalInstance);
-      const value = transformedInstance.generate(mrng, runId);
-      const shrink2Value = transformedInstance.shrink(value).getNthOrLast(1)!;
-      const shrinks = transformedInstance.shrink(shrink2Value);
-
-      // Assert
-      expect([...shrinks].map((v) => v.value)).toEqual([expectedShrink21]);
-    });
-  });
-});
diff --git a/test/unit/check/property/ConvertersProperty.spec.ts b/test/unit/check/property/ConvertersProperty.spec.ts
deleted file mode 100644
index 982d1ae5..00000000
--- a/test/unit/check/property/ConvertersProperty.spec.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-import { NextValue } from '../../../../src/check/arbitrary/definition/NextValue';
-import { Shrinkable } from '../../../../src/check/arbitrary/definition/Shrinkable';
-import { PreconditionFailure } from '../../../../src/check/precondition/PreconditionFailure';
-import { INextRawProperty } from '../../../../src/check/property/INextRawProperty';
-import { IRawProperty } from '../../../../src/check/property/IRawProperty';
-import { Random } from '../../../../src/random/generator/Random';
-import { Stream } from '../../../../src/stream/Stream';
-import { convertFromNextProperty, convertToNextProperty } from '../../../../src/check/property/ConvertersProperty';
-
-describe('Converters (integration)', () => {
-  it('should return the original instance of IRawProperty when calling convertFromNextProperty(convertToNextProperty)', () => {
-    // Arrange
-    class MyProperty implements IRawProperty<number, false> {
-      isAsync(): false {
-        throw new Error('Method not implemented.');
-      }
-      generate(_mrng: Random, _runId?: number): Shrinkable<number, number> {
-        throw new Error('Method not implemented.');
-      }
-      run(_v: number): string | PreconditionFailure {
-        throw new Error('Method not implemented.');
-      }
-    }
-    const originalInstance = new MyProperty();
-
-    // Act
-    const transformedInstance = convertFromNextProperty(convertToNextProperty(originalInstance));
-
-    // Assert
-    expect(transformedInstance).toBe(originalInstance);
-  });
-
-  it('should return the original instance of IRawNextProperty when calling convertToNextProperty(convertFromNextProperty)', () => {
-    // Arrange
-    class MyNextProperty implements INextRawProperty<number, false> {
-      isAsync(): false {
-        throw new Error('Method not implemented.');
-      }
-      generate(_mrng: Random, _runId?: number): NextValue<number> {
-        throw new Error('Method not implemented.');
-      }
-      shrink(_value: NextValue<number>): Stream<NextValue<number>> {
-        throw new Error('Method not implemented.');
-      }
-      run(_v: number): string | PreconditionFailure {
-        throw new Error('Method not implemented.');
-      }
-    }
-    const originalInstance = new MyNextProperty();
-
-    // Act
-    const transformedInstance = convertToNextProperty(convertFromNextProperty(originalInstance));
-
-    // Assert
-    expect(transformedInstance).toBe(originalInstance);
-  });
-});
diff --git a/test/unit/check/property/IgnoreEqualValuesProperty.spec.ts b/test/unit/check/property/IgnoreEqualValuesProperty.spec.ts
index 75f8cbe7..5fd43bc3 100644
--- a/test/unit/check/property/IgnoreEqualValuesProperty.spec.ts
+++ b/test/unit/check/property/IgnoreEqualValuesProperty.spec.ts
@@ -1,6 +1,6 @@
 import { IgnoreEqualValuesProperty } from '../../../../src/check/property/IgnoreEqualValuesProperty';
 import { PreconditionFailure } from '../../../../src/check/precondition/PreconditionFailure';
-import { fakeNextProperty } from './__test-helpers__/PropertyHelpers';
+import { fakeProperty } from './__test-helpers__/PropertyHelpers';
 
 describe('IgnoreEqualValuesProperty', () => {
   it.each`
@@ -9,7 +9,7 @@ describe('IgnoreEqualValuesProperty', () => {
     ${true}
   `('should not call run on the decorated property when property is run on the same value', ({ skipRuns }) => {
     // Arrange
-    const { instance: decoratedProperty, run } = fakeNextProperty();
+    const { instance: decoratedProperty, run } = fakeProperty();
 
     // Act
     const property = new IgnoreEqualValuesProperty(decoratedProperty, skipRuns);
@@ -35,7 +35,7 @@ describe('IgnoreEqualValuesProperty', () => {
       // success -> success
       // failure -> failure
       // skip    -> skip
-      const { instance: decoratedProperty, run } = fakeNextProperty(isAsync);
+      const { instance: decoratedProperty, run } = fakeProperty(isAsync);
       run.mockImplementation(() => (isAsync ? Promise.resolve(originalValue) : originalValue));
 
       // Act
@@ -63,7 +63,7 @@ describe('IgnoreEqualValuesProperty', () => {
       // success -> skip
       // failure -> failure
       // skip    -> skip
-      const { instance: decoratedProperty, run } = fakeNextProperty(isAsync);
+      const { instance: decoratedProperty, run } = fakeProperty(isAsync);
       run.mockImplementation(() => (isAsync ? Promise.resolve(originalValue) : originalValue));
 
       // Act
@@ -89,7 +89,7 @@ describe('IgnoreEqualValuesProperty', () => {
     ${true}
   `('should run decorated property when property is run on another value', ({ skipRuns }) => {
     // Arrange
-    const { instance: decoratedProperty, run } = fakeNextProperty();
+    const { instance: decoratedProperty, run } = fakeProperty();
 
     // Act
     const property = new IgnoreEqualValuesProperty(decoratedProperty, skipRuns);
diff --git a/test/unit/check/property/Property.spec.ts b/test/unit/check/property/Property.spec.ts
index ca3ffca8..c810128c 100644
--- a/test/unit/check/property/Property.spec.ts
+++ b/test/unit/check/property/Property.spec.ts
@@ -9,7 +9,6 @@ import * as stubArb from '../../stubs/arbitraries';
 import * as stubRng from '../../stubs/generators';
 import { fakeNextArbitrary } from '../../arbitrary/__test-helpers__/NextArbitraryHelpers';
 import { convertFromNext } from '../../../../src/check/arbitrary/definition/Converters';
-import { convertToNextProperty } from '../../../../src/check/property/ConvertersProperty';
 import { NextValue } from '../../../../src/check/arbitrary/definition/NextValue';
 import { Stream } from '../../../../src/stream/Stream';
 
@@ -251,7 +250,7 @@ describe('Property', () => {
     const value = Symbol();
 
     // Act
-    const p = convertToNextProperty(property(convertFromNext(arb), jest.fn()));
+    const p = property(convertFromNext(arb), jest.fn());
     const shrinks = p.shrink(new NextValue([value], undefined)); // context=undefined in the case of user defined values
 
     // Assert
@@ -270,7 +269,7 @@ describe('Property', () => {
     const value = Symbol();
 
     // Act
-    const p = convertToNextProperty(property(convertFromNext(arb), jest.fn()));
+    const p = property(convertFromNext(arb), jest.fn());
     const shrinks = p.shrink(new NextValue([value], undefined)); // context=undefined in the case of user defined values
 
     // Assert
diff --git a/test/unit/check/property/SkipAfterProperty.spec.ts b/test/unit/check/property/SkipAfterProperty.spec.ts
index 3ce870fc..ac94fd56 100644
--- a/test/unit/check/property/SkipAfterProperty.spec.ts
+++ b/test/unit/check/property/SkipAfterProperty.spec.ts
@@ -1,6 +1,6 @@
 import { SkipAfterProperty } from '../../../../src/check/property/SkipAfterProperty';
 import { PreconditionFailure } from '../../../../src/check/precondition/PreconditionFailure';
-import { fakeNextProperty } from './__test-helpers__/PropertyHelpers';
+import { fakeProperty } from './__test-helpers__/PropertyHelpers';
 import { fakeRandom } from '../../arbitrary/__test-helpers__/RandomHelpers';
 import { NextValue } from '../../../../src/check/arbitrary/definition/NextValue';
 
@@ -11,7 +11,7 @@ describe('SkipAfterProperty', () => {
   it('should call timer at construction', async () => {
     // Arrange
     const timerMock = jest.fn();
-    const { instance: decoratedProperty } = fakeNextProperty();
+    const { instance: decoratedProperty } = fakeProperty();
 
     // Act
     new SkipAfterProperty(decoratedProperty, timerMock, 0, false);
@@ -23,7 +23,7 @@ describe('SkipAfterProperty', () => {
   it('should not call timer on isAsync but forward call', async () => {
     // Arrange
     const timerMock = jest.fn();
-    const { instance: decoratedProperty, isAsync, generate, shrink, run } = fakeNextProperty();
+    const { instance: decoratedProperty, isAsync, generate, shrink, run } = fakeProperty();
 
     // Act
     const p = new SkipAfterProperty(decoratedProperty, timerMock, 0, false);
@@ -40,7 +40,7 @@ describe('SkipAfterProperty', () => {
   it('should not call timer on generate but forward call', async () => {
     // Arrange
     const timerMock = jest.fn();
-    const { instance: decoratedProperty, isAsync, generate, shrink, run } = fakeNextProperty();
+    const { instance: decoratedProperty, isAsync, generate, shrink, run } = fakeProperty();
     const { instance: mrng } = fakeRandom();
 
     // Act
@@ -58,7 +58,7 @@ describe('SkipAfterProperty', () => {
   it('should not call timer on shrink but forward call', async () => {
     // Arrange
     const timerMock = jest.fn();
-    const { instance: decoratedProperty, isAsync, generate, shrink, run } = fakeNextProperty();
+    const { instance: decoratedProperty, isAsync, generate, shrink, run } = fakeProperty();
 
     // Act
     const p = new SkipAfterProperty(decoratedProperty, timerMock, 0, false);
@@ -75,7 +75,7 @@ describe('SkipAfterProperty', () => {
   it('should call timer on run and forward call if ok', () => {
     // Arrange
     const timerMock = jest.fn();
-    const { instance: decoratedProperty, isAsync, generate, shrink, run } = fakeNextProperty();
+    const { instance: decoratedProperty, isAsync, generate, shrink, run } = fakeProperty();
 
     // Act
     const p = new SkipAfterProperty(decoratedProperty, timerMock, 0, false);
@@ -95,7 +95,7 @@ describe('SkipAfterProperty', () => {
       .fn()
       .mockReturnValueOnce(startTimeMs)
       .mockReturnValueOnce(startTimeMs + timeLimitMs);
-    const { instance: decoratedProperty, isAsync, generate, shrink, run } = fakeNextProperty();
+    const { instance: decoratedProperty, isAsync, generate, shrink, run } = fakeProperty();
 
     // Act
     const p = new SkipAfterProperty(decoratedProperty, timerMock, 0, false);
@@ -116,7 +116,7 @@ describe('SkipAfterProperty', () => {
       .fn()
       .mockReturnValueOnce(startTimeMs)
       .mockReturnValueOnce(startTimeMs + timeLimitMs);
-    const { instance: decoratedProperty } = fakeNextProperty();
+    const { instance: decoratedProperty } = fakeProperty();
 
     // Act
     const p = new SkipAfterProperty(decoratedProperty, timerMock, 0, false);
@@ -133,7 +133,7 @@ describe('SkipAfterProperty', () => {
       .fn()
       .mockReturnValueOnce(startTimeMs)
       .mockReturnValueOnce(startTimeMs + timeLimitMs);
-    const { instance: decoratedProperty } = fakeNextProperty();
+    const { instance: decoratedProperty } = fakeProperty();
 
     // Act
     const p = new SkipAfterProperty(decoratedProperty, timerMock, 0, true);
diff --git a/test/unit/check/property/TimeoutProperty.spec.ts b/test/unit/check/property/TimeoutProperty.spec.ts
index 8fc28fc6..db78cfb2 100644
--- a/test/unit/check/property/TimeoutProperty.spec.ts
+++ b/test/unit/check/property/TimeoutProperty.spec.ts
@@ -1,7 +1,7 @@
 import { NextValue } from '../../../../src/check/arbitrary/definition/NextValue';
 import { TimeoutProperty } from '../../../../src/check/property/TimeoutProperty';
 import { fakeRandom } from '../../arbitrary/__test-helpers__/RandomHelpers';
-import { fakeNextProperty } from './__test-helpers__/PropertyHelpers';
+import { fakeProperty } from './__test-helpers__/PropertyHelpers';
 
 describe('TimeoutProperty', () => {
   beforeEach(() => {
@@ -11,7 +11,7 @@ describe('TimeoutProperty', () => {
   it('should forward calls to generate', () => {
     // Arrange
     jest.useFakeTimers();
-    const { instance: decoratedProperty, generate } = fakeNextProperty(true);
+    const { instance: decoratedProperty, generate } = fakeProperty(true);
     const { instance: mrng } = fakeRandom();
     const expectedRunId = 42;
     const expectedOut = new NextValue(Symbol('value'), Symbol('context'));
@@ -30,7 +30,7 @@ describe('TimeoutProperty', () => {
   it('should forward inputs to run', async () => {
     // Arrange
     jest.useFakeTimers();
-    const { instance: decoratedProperty, run } = fakeNextProperty(true);
+    const { instance: decoratedProperty, run } = fakeProperty(true);
     const expectedRunInput = { anything: Symbol('something') };
 
     // Act
@@ -47,7 +47,7 @@ describe('TimeoutProperty', () => {
   it('should not timeout if it succeeds in time', async () => {
     // Arrange
     jest.useFakeTimers();
-    const { instance: decoratedProperty, run } = fakeNextProperty(true);
+    const { instance: decoratedProperty, run } = fakeProperty(true);
     run.mockReturnValueOnce(
       new Promise(function (resolve) {
         setTimeout(() => resolve(null), 10);
@@ -67,7 +67,7 @@ describe('TimeoutProperty', () => {
   it('should not timeout if it fails in time', async () => {
     // Arrange
     jest.useFakeTimers();
-    const { instance: decoratedProperty, run } = fakeNextProperty(true);
+    const { instance: decoratedProperty, run } = fakeProperty(true);
     run.mockReturnValueOnce(
       new Promise(function (resolve) {
         // underlying property is not supposed to throw (reject)
@@ -88,7 +88,7 @@ describe('TimeoutProperty', () => {
   it('should clear all started timeouts on success', async () => {
     // Arrange
     jest.useFakeTimers();
-    const { instance: decoratedProperty, run } = fakeNextProperty(true);
+    const { instance: decoratedProperty, run } = fakeProperty(true);
     run.mockResolvedValueOnce(null);
 
     // Act
@@ -103,7 +103,7 @@ describe('TimeoutProperty', () => {
   it('should clear all started timeouts on failure', async () => {
     // Arrange
     jest.useFakeTimers();
-    const { instance: decoratedProperty, run } = fakeNextProperty(true);
+    const { instance: decoratedProperty, run } = fakeProperty(true);
     run.mockResolvedValueOnce('plop');
 
     // Act
@@ -118,7 +118,7 @@ describe('TimeoutProperty', () => {
   it('should timeout if it takes to long', async () => {
     // Arrange
     jest.useFakeTimers();
-    const { instance: decoratedProperty, run } = fakeNextProperty(true);
+    const { instance: decoratedProperty, run } = fakeProperty(true);
     run.mockReturnValueOnce(
       new Promise(function (resolve) {
         setTimeout(() => resolve(null), 100);
@@ -137,7 +137,7 @@ describe('TimeoutProperty', () => {
   it('Should timeout if it never ends', async () => {
     // Arrange
     jest.useFakeTimers();
-    const { instance: decoratedProperty, run } = fakeNextProperty(true);
+    const { instance: decoratedProperty, run } = fakeProperty(true);
     run.mockReturnValueOnce(new Promise(() => {}));
 
     // Act
diff --git a/test/unit/check/property/UnbiasedProperty.spec.ts b/test/unit/check/property/UnbiasedProperty.spec.ts
index 4ea213e1..7747ef28 100644
--- a/test/unit/check/property/UnbiasedProperty.spec.ts
+++ b/test/unit/check/property/UnbiasedProperty.spec.ts
@@ -1,11 +1,11 @@
 import { UnbiasedProperty } from '../../../../src/check/property/UnbiasedProperty';
 import { fakeRandom } from '../../arbitrary/__test-helpers__/RandomHelpers';
-import { fakeNextProperty } from './__test-helpers__/PropertyHelpers';
+import { fakeProperty } from './__test-helpers__/PropertyHelpers';
 
 describe('UnbiasedProperty', () => {
   it('should not pass runId towards the decorated property on generate', () => {
     // Arrange
-    const { instance: decoratedProperty, generate } = fakeNextProperty();
+    const { instance: decoratedProperty, generate } = fakeProperty();
     const { instance: mrng } = fakeRandom();
 
     // Act
diff --git a/test/unit/check/property/__test-helpers__/PropertyHelpers.ts b/test/unit/check/property/__test-helpers__/PropertyHelpers.ts
index 4f179046..7973a521 100644
--- a/test/unit/check/property/__test-helpers__/PropertyHelpers.ts
+++ b/test/unit/check/property/__test-helpers__/PropertyHelpers.ts
@@ -1,12 +1,12 @@
 import { MaybeMocked } from 'ts-jest/dist/utils/testing';
-import { INextRawProperty } from '../../../../../src/check/property/INextRawProperty';
+import { IRawProperty } from '../../../../../src/check/property/IRawProperty';
 
 /**
- * Generate a fake instance inheriting from INextRawProperty with all methods being mocked
+ * Generate a fake instance inheriting from IRawProperty with all methods being mocked
  */
-export function fakeNextProperty<T = unknown, TIsAsync extends boolean = boolean>(
+export function fakeProperty<T = unknown, TIsAsync extends boolean = boolean>(
   isAsyncResponse?: TIsAsync
-): { instance: INextRawProperty<T, TIsAsync> } & MaybeMocked<INextRawProperty<T, TIsAsync>> {
+): { instance: IRawProperty<T, TIsAsync> } & MaybeMocked<IRawProperty<T, TIsAsync>> {
   const isAsync = jest.fn();
   if (isAsyncResponse !== undefined) {
     isAsync.mockReturnValue(isAsyncResponse);
@@ -14,7 +14,7 @@ export function fakeNextProperty<T = unknown, TIsAsync extends boolean = boolean
   const generate = jest.fn();
   const shrink = jest.fn();
   const run = jest.fn();
-  class MyProperty implements INextRawProperty<unknown, boolean> {
+  class MyProperty implements IRawProperty<unknown, boolean> {
     isAsync = isAsync;
     generate = generate;
     shrink = shrink;
diff --git a/test/unit/check/runner/DecorateProperty.spec.ts b/test/unit/check/runner/DecorateProperty.spec.ts
index 153b92f3..fbff6fe2 100644
--- a/test/unit/check/runner/DecorateProperty.spec.ts
+++ b/test/unit/check/runner/DecorateProperty.spec.ts
@@ -1,6 +1,7 @@
 import { decorateProperty } from '../../../../src/check/runner/DecorateProperty';
 import { IRawProperty } from '../../../../src/check/property/IRawProperty';
-import { Shrinkable } from '../../../../src/check/arbitrary/definition/Shrinkable';
+import { NextValue } from '../../../../src/check/arbitrary/definition/NextValue';
+import { Stream } from '../../../../src/stream/Stream';
 
 // Mocks
 import { SkipAfterProperty } from '../../../../src/check/property/SkipAfterProperty';
@@ -15,7 +16,8 @@ jest.mock('../../../../src/check/property/IgnoreEqualValuesProperty');
 function buildProperty(asyncProp: boolean) {
   return {
     isAsync: () => asyncProp,
-    generate: () => new Shrinkable({}),
+    generate: () => new NextValue({}, undefined),
+    shrink: () => Stream.nil(),
     run: () => null,
   } as IRawProperty<any>;
 }
diff --git a/test/unit/check/runner/Runner.spec.ts b/test/unit/check/runner/Runner.spec.ts
index 9666c0d5..a1067913 100644
--- a/test/unit/check/runner/Runner.spec.ts
+++ b/test/unit/check/runner/Runner.spec.ts
@@ -1,13 +1,13 @@
 import * as fc from '../../../../lib/fast-check';
 
-import { Shrinkable } from '../../../../src/check/arbitrary/definition/Shrinkable';
+import { NextValue } from '../../../../src/check/arbitrary/definition/NextValue';
 import { char } from '../../../../src/arbitrary/char';
 import { IRawProperty } from '../../../../src/check/property/IRawProperty';
 import { check, assert as rAssert } from '../../../../src/check/runner/Runner';
 import { Random } from '../../../../src/random/generator/Random';
 import { RunDetails } from '../../../../src/check/runner/reporter/RunDetails';
 import { PreconditionFailure } from '../../../../src/check/precondition/PreconditionFailure';
-import { stream, Stream } from '../../../../src/stream/Stream';
+import { Stream } from '../../../../src/stream/Stream';
 import { VerbosityLevel } from '../../../../src/check/runner/configuration/VerbosityLevel';
 
 const MAX_NUM_RUNS = 1000;
@@ -29,7 +29,8 @@ describe('Runner', () => {
     `('Should throw if both reporter and asyncReporter are defined (isAsync: $isAsync)', ({ isAsync }) => {
       const p: IRawProperty<[number]> = {
         isAsync: () => isAsync,
-        generate: () => new Shrinkable([0]),
+        generate: () => new NextValue([0], undefined),
+        shrink: () => Stream.nil(),
         run: () => null,
       };
       expect(() => check(p, { reporter: () => {}, asyncReporter: async () => {} })).toThrowError();
@@ -37,7 +38,8 @@ describe('Runner', () => {
     it('Should not throw if reporter is specified on synchronous properties', () => {
       const p: IRawProperty<[number]> = {
         isAsync: () => false,
-        generate: () => new Shrinkable([0]),
+        generate: () => new NextValue([0], undefined),
+        shrink: () => Stream.nil(),
         run: () => null,
       };
       expect(() => check(p, { reporter: () => {} })).not.toThrowError();
@@ -45,7 +47,8 @@ describe('Runner', () => {
     it('Should not throw if reporter is specified on asynchronous properties', () => {
       const p: IRawProperty<[number]> = {
         isAsync: () => true,
-        generate: () => new Shrinkable([0]),
+        generate: () => new NextValue([0], undefined),
+        shrink: () => Stream.nil(),
         run: () => null,
       };
       expect(() => check(p, { reporter: () => {} })).not.toThrowError();
@@ -53,7 +56,8 @@ describe('Runner', () => {
     it('Should throw if asyncReporter is specified on synchronous properties', () => {
       const p: IRawProperty<[number]> = {
         isAsync: () => false,
-        generate: () => new Shrinkable([0]),
+        generate: () => new NextValue([0], undefined),
+        shrink: () => Stream.nil(),
         run: () => null,
       };
       expect(() => check(p, { asyncReporter: async () => {} })).toThrowError();
@@ -61,7 +65,8 @@ describe('Runner', () => {
     it('Should not throw if asyncReporter is specified on asynchronous properties', () => {
       const p: IRawProperty<[number]> = {
         isAsync: () => true,
-        generate: () => new Shrinkable([0]),
+        generate: () => new NextValue([0], undefined),
+        shrink: () => Stream.nil(),
         run: () => null,
       };
       expect(() => check(p, { asyncReporter: async () => {} })).not.toThrowError();
@@ -74,8 +79,9 @@ describe('Runner', () => {
         generate: () => {
           expect(numCallsRun).toEqual(numCallsGenerate); // called run before calling back
           ++numCallsGenerate;
-          return new Shrinkable([numCallsGenerate]) as Shrinkable<[number]>;
+          return new NextValue([numCallsGenerate] as [number], undefined);
         },
+        shrink: () => Stream.nil(),
         run: (value: [number]) => {
           expect(value[0]).toEqual(numCallsGenerate); // called with previously generated value
           ++numCallsRun;
@@ -95,8 +101,9 @@ describe('Runner', () => {
         generate: () => {
           expect(numCallsRun).toEqual(numCallsGenerate); // called run before calling back
           ++numCallsGenerate;
-          return new Shrinkable([numCallsGenerate]) as Shrinkable<[number]>;
+          return new NextValue([numCallsGenerate] as [number], undefined);
         },
+        shrink: () => Stream.nil(),
         run: (value: [number]) => {
           expect(value[0]).toEqual(numCallsGenerate); // called with previously generated value
           ++numCallsRun;
@@ -115,10 +122,18 @@ describe('Runner', () => {
         isAsync: () => false,
         generate: () => {
           ++numCallsGenerate;
+          return new NextValue<[number]>([0], 'shrink-me');
+        },
+        shrink: (value) => {
           function* g() {
-            for (let i = 0; i !== 1234; ++i) yield new Shrinkable<[number]>([0]);
+            if (value.context !== 'shrink-me') {
+              return;
+            }
+            for (let i = 0; i !== 1234; ++i) {
+              yield new NextValue<[number]>([0], undefined);
+            }
           }
-          return new Shrinkable<[number]>([0], () => stream(g()));
+          return new Stream(g());
         },
         run: () => {
           ++numCallsRun;
@@ -148,7 +163,8 @@ describe('Runner', () => {
             let numCallsRun = 0;
             const p: IRawProperty<[number]> = {
               isAsync: () => isAsyncProp,
-              generate: () => new Shrinkable([numCallsGenerate++]) as Shrinkable<[number]>,
+              generate: () => new NextValue([numCallsGenerate++] as [number], undefined),
+              shrink: () => Stream.nil(),
               run: (value: [number]) => {
                 ++numCallsRun;
                 const successId = successIds.indexOf(value[0]);
@@ -188,7 +204,8 @@ describe('Runner', () => {
             let numPreconditionFailures = 0;
             const p: IRawProperty<[number]> = {
               isAsync: () => isAsyncProp,
-              generate: () => new Shrinkable([numCallsGenerate++]) as Shrinkable<[number]>,
+              generate: () => new NextValue([numCallsGenerate++] as [number], undefined),
+              shrink: () => Stream.nil(),
               run: (value: [number]) => {
                 if (value[0] === settings.onlySuccessId) return null;
                 ++numPreconditionFailures;
@@ -213,9 +230,10 @@ describe('Runner', () => {
         isAsync: () => false,
         generate: () => {
           ++numCallsGenerate;
-          return new Shrinkable([0], () => {
-            throw 'Not implemented';
-          }) as Shrinkable<[number]>;
+          return new NextValue([0], undefined);
+        },
+        shrink: () => {
+          throw 'Not implemented';
         },
         run: (_value: [number]) => {
           ++numCallsRun;
@@ -236,8 +254,9 @@ describe('Runner', () => {
             isAsync: () => false,
             generate: () => {
               ++numCallsGenerate;
-              return new Shrinkable([0]) as Shrinkable<[number]>;
+              return new NextValue([0], undefined);
             },
+            shrink: () => Stream.nil(),
             run: (_value: [number]) => {
               return ++numCallsRun < num ? null : 'error';
             },
@@ -260,8 +279,9 @@ describe('Runner', () => {
             isAsync: () => false,
             generate: () => {
               ++numCallsGenerate;
-              return new Shrinkable([0]) as Shrinkable<[number]>;
+              return new NextValue([0], undefined);
             },
+            shrink: () => Stream.nil(),
             run: (_value: [number]) => {
               ++numCallsRun;
               return null;
@@ -281,8 +301,9 @@ describe('Runner', () => {
             const p: IRawProperty<[number]> = {
               isAsync: () => false,
               generate: (rng: Random) => {
-                return new Shrinkable([rng.nextInt()]) as Shrinkable<[number]>;
+                return new NextValue([rng.nextInt()], undefined);
               },
+              shrink: () => Stream.nil(),
               run: (value: [number]) => {
                 runOn.push(value[0]);
                 return null;
@@ -302,9 +323,10 @@ describe('Runner', () => {
       const p: IRawProperty<[number]> = {
         isAsync: () => false,
         generate: () => {
-          return new Shrinkable([0], () => {
-            throw 'Not implemented';
-          }) as Shrinkable<[number]>;
+          return new NextValue([0], undefined);
+        },
+        shrink: () => {
+          throw 'Not implemented';
         },
         run: (_value: [number]) => {
           return 'failure';
@@ -318,12 +340,13 @@ describe('Runner', () => {
       const p: IRawProperty<[number]> = {
         isAsync: () => false,
         generate: () => {
-          const g = function* () {
-            yield new Shrinkable([42], () => {
-              throw 'Not implemented';
-            }) as Shrinkable<[number]>;
-          };
-          return new Shrinkable([0], () => stream(g())) as Shrinkable<[number]>;
+          return new NextValue([0], undefined);
+        },
+        shrink: (value) => {
+          if (value.value[0] !== 0) {
+            throw 'Not implemented';
+          }
+          return Stream.of(new NextValue([42], undefined));
         },
         run: (value: [number]) => {
           return value[0] === 42 ? 'failure' : null;
@@ -336,20 +359,22 @@ describe('Runner', () => {
     it('Should not provide list of failures by default (no verbose)', () => {
       const p: IRawProperty<[number]> = {
         isAsync: () => false,
-        generate: () => new Shrinkable([42]) as Shrinkable<[number]>,
+        generate: () => new NextValue([42], undefined),
+        shrink: () => Stream.nil(),
         run: () => 'failure',
       };
       const out = check(p) as RunDetails<[number]>;
       expect(out.failures).toHaveLength(0);
     });
     it('Should provide the list of failures in verbose mode', () => {
-      const g = function* () {
-        yield new Shrinkable([48]) as Shrinkable<[number]>;
-        yield new Shrinkable([12]) as Shrinkable<[number]>;
-      };
       const p: IRawProperty<[number]> = {
         isAsync: () => false,
-        generate: () => new Shrinkable([42], () => stream(g())) as Shrinkable<[number]>,
+        generate: () => new NextValue([42], undefined),
+        shrink: (value) => {
+          return value.value[0] === 42
+            ? Stream.of(new NextValue([48], undefined), new NextValue([12], undefined))
+            : Stream.nil();
+        },
         run: () => 'failure',
       };
       const out = check(p, { verbose: true }) as RunDetails<[number]>;
@@ -364,19 +389,21 @@ describe('Runner', () => {
           // Basically it must fail before the end of the execution (100 runs by default)
           // so failure points are between 0 and 99 inclusive
 
-          const deepShrinkable = function (depth: number): Shrinkable<[number]> {
-            if (depth <= 0) return new Shrinkable([0]) as Shrinkable<[number]>;
-            function* g(subDepth: number): IterableIterator<Shrinkable<[number]>> {
-              while (true) yield deepShrinkable(subDepth);
-            }
-            return new Shrinkable([0], () => stream(g(depth - 1))) as Shrinkable<[number]>;
-          };
-
           let idx = 0;
           let remainingBeforeFailure = failurePoints[idx];
           const p: IRawProperty<[number]> = {
             isAsync: () => false,
-            generate: (_mrng: Random) => deepShrinkable(failurePoints.length - 1),
+            generate: (_mrng: Random) => new NextValue([0], failurePoints.length - 1),
+            shrink: (value) => {
+              const depth = value.context as number;
+              if (depth <= 0) {
+                return Stream.nil();
+              }
+              function* g(): IterableIterator<NextValue<[number]>> {
+                while (true) yield new NextValue([0], depth - 1);
+              }
+              return new Stream(g());
+            },
             run: (_value: [number]) => {
               if (--remainingBeforeFailure >= 0) return null;
               remainingBeforeFailure = failurePoints[++idx];
@@ -405,11 +432,10 @@ describe('Runner', () => {
             isAsync: () => true,
             generate: () => {
               ++numCallsGenerate;
-              const shrinkedValue = new Shrinkable([42]) as Shrinkable<[number]>;
-              const g = function* () {
-                yield shrinkedValue;
-              };
-              return new Shrinkable([1], () => new Stream(g())) as Shrinkable<[number]>;
+              return new NextValue([1], undefined);
+            },
+            shrink: (value) => {
+              return value.value[0] === 1 ? Stream.of(new NextValue([42], undefined)) : Stream.nil();
             },
             run: async (_value: [number]) => {
               await new Promise<void>((resolve) => {
@@ -445,7 +471,8 @@ describe('Runner', () => {
     it('Should not timeout if no timeout defined', async () => {
       const p: IRawProperty<[number]> = {
         isAsync: () => true,
-        generate: () => new Shrinkable([1]) as Shrinkable<[number]>,
+        generate: () => new NextValue([1], undefined),
+        shrink: () => Stream.nil(),
         run: async (_value: [number]) => null,
       };
       const out = await (check(p) as Promise<RunDetails<[number]>>);
@@ -455,7 +482,8 @@ describe('Runner', () => {
       const wait = (timeMs: number) => new Promise<null>((resolve) => setTimeout(() => resolve(null), timeMs));
       const p: IRawProperty<[number]> = {
         isAsync: () => true,
-        generate: () => new Shrinkable([1]) as Shrinkable<[number]>,
+        generate: () => new NextValue([1], undefined),
+        shrink: () => Stream.nil(),
         run: async (_value: [number]) => await wait(0),
       };
       const out = await (check(p, { timeout: 100 }) as Promise<RunDetails<[number]>>);
@@ -465,7 +493,8 @@ describe('Runner', () => {
       const wait = (timeMs: number) => new Promise<null>((resolve) => setTimeout(() => resolve(null), timeMs));
       const p: IRawProperty<[number]> = {
         isAsync: () => true,
-        generate: () => new Shrinkable([1]) as Shrinkable<[number]>,
+        generate: () => new NextValue([1], undefined),
+        shrink: () => Stream.nil(),
         run: async (_value: [number]) => await wait(100),
       };
       const out = await (check(p, { timeout: 0 }) as Promise<RunDetails<[number]>>);
@@ -475,7 +504,8 @@ describe('Runner', () => {
       const neverEnds = () => new Promise<null>(() => {});
       const p: IRawProperty<[number]> = {
         isAsync: () => true,
-        generate: () => new Shrinkable([1]) as Shrinkable<[number]>,
+        generate: () => new NextValue([1], undefined),
+        shrink: () => Stream.nil(),
         run: async (_value: [number]) => await neverEnds(),
       };
       const out = await (check(p, { timeout: 0 }) as Promise<RunDetails<[number]>>);
@@ -487,17 +517,20 @@ describe('Runner', () => {
     const v2 = { a: 'Hello', b: 21 };
     const failingProperty: IRawProperty<[any, any]> = {
       isAsync: () => false,
-      generate: () => new Shrinkable([v1, v2]) as Shrinkable<[any, any]>,
+      generate: () => new NextValue([v1, v2], undefined),
+      shrink: () => Stream.nil(),
       run: (_v: [any, any]) => 'error in failingProperty',
     };
     const failingComplexProperty: IRawProperty<[any, any, any]> = {
       isAsync: () => false,
-      generate: () => new Shrinkable([[v1, v2], v2, v1]) as Shrinkable<[any, any, any]>,
+      generate: () => new NextValue([[v1, v2], v2, v1], undefined),
+      shrink: () => Stream.nil(),
       run: (_v: [any, any, any]) => 'error in failingComplexProperty',
     };
     const successProperty: IRawProperty<[any, any]> = {
       isAsync: () => false,
-      generate: () => new Shrinkable([v1, v2]) as Shrinkable<[any, any]>,
+      generate: () => new NextValue([v1, v2], undefined),
+      shrink: () => Stream.nil(),
       run: (_v: [any, any]) => null,
     };
 
@@ -538,11 +571,12 @@ describe('Runner', () => {
       const p: IRawProperty<[number]> = {
         isAsync: () => false,
         generate: () => {
-          const g = function* () {
-            yield new Shrinkable([48]) as Shrinkable<[number]>;
-            yield new Shrinkable([12]) as Shrinkable<[number]>;
-          };
-          return new Shrinkable([42], () => stream(g())) as Shrinkable<[number]>;
+          return new NextValue([42], undefined);
+        },
+        shrink: (value) => {
+          return value.value[0] === 42
+            ? Stream.of(new NextValue([48], undefined), new NextValue([12], undefined))
+            : Stream.nil();
         },
         run: () => 'failure',
       };
@@ -580,7 +614,8 @@ describe('Runner', () => {
       const baseErrorMessage = 'Failed to run property, too many pre-condition failures encountered';
       const p: IRawProperty<[number]> = {
         isAsync: () => false,
-        generate: () => new Shrinkable([42]) as Shrinkable<[number]>,
+        generate: () => new NextValue([42], undefined),
+        shrink: () => Stream.nil(),
         run: () => new PreconditionFailure(),
       };
       it('Should throw with base message by default (no verbose)', () => {
diff --git a/test/unit/check/runner/Tosser.spec.ts b/test/unit/check/runner/Tosser.spec.ts
index b0208315..2749a721 100644
--- a/test/unit/check/runner/Tosser.spec.ts
+++ b/test/unit/check/runner/Tosser.spec.ts
@@ -3,15 +3,15 @@ import * as fc from '../../../../lib/fast-check';
 import { toss } from '../../../../src/check/runner/Tosser';
 import { Stream, stream } from '../../../../src/stream/Stream';
 import { Arbitrary } from '../../../../src/check/arbitrary/definition/Arbitrary';
-import { INextRawProperty } from '../../../../src/check/property/INextRawProperty';
+import { IRawProperty } from '../../../../src/check/property/IRawProperty';
 import { Random } from '../../../../src/random/generator/Random';
 import { NextValue } from '../../../../src/check/arbitrary/definition/NextValue';
 
 import * as stubArb from '../../stubs/arbitraries';
 import prand from 'pure-rand';
 
-const wrap = <T>(arb: Arbitrary<T>): INextRawProperty<T> =>
-  new (class implements INextRawProperty<T> {
+const wrap = <T>(arb: Arbitrary<T>): IRawProperty<T> =>
+  new (class implements IRawProperty<T> {
     constructor(readonly arb: Arbitrary<T>) {}
     isAsync = () => false;
     generate = (rng: Random) => new NextValue(this.arb.generate(rng).value_, undefined);