Skip to main content
Every guard in ts-chas/guard exposes two async methods for producing valid test data: .generate() for quick sampling and .arbitrary() for deep integration with fast-check. Both are derived directly from the guard’s constraint chain, so the same guard that validates your data also drives its generation. No separate schemas or factory functions to maintain. fast-check is a peer dependency and must be installed separately:

.generate()

Returns a Promise<T> when called with no argument, or Promise<T[]> when called with a count. Generated values are guaranteed to pass the guard’s predicate.

Quick examples

Data-driven tests with it.each

A common pattern is to generate a batch of valid inputs and feed them to parameterized tests:

.arbitrary()

Returns a Promise<Arbitrary<T>> — a fully configured fast-check Arbitrary that you can compose, transform, and use directly in fc.assert property tests.

Property-based testing

Composing arbitraries

Because .arbitrary() returns a standard fast-check Arbitrary, you can use .map(), .filter(), and .chain() on it:

Combining multiple guards


Constraint coverage

The generator reads constraints from the guard’s accumulated metadata and translates them to tight arbitraries. What follows is a full reference for every supported helper.

Strings

Numbers

BigInts

BigInt has no native JSON Schema representation, so constraints are stored as internal markers.

Booleans

Dates

Dates are always generated within the year range 1000-9000 by default, so .toISOString() never throws.

URLs

is.url() returns a URL guard (not a string guard). Constraints from URL helpers are reflected in generation:

Arrays

Tuples

Fixed-position tuples generate the correct type at each index:
Variadic tuples append rest elements after the fixed positions:

Objects

Shaped objects generate a value for every key in the schema. Optional and nullable fields are handled automatically:

Records

is.record(keyGuard, valueGuard) generates plain objects whose keys satisfy keyGuard and whose values satisfy valueGuard:
When the key guard has a finite value set (literals or enums), those exact keys are used.

Maps and Sets

Sets use fc.uniqueArray internally so size constraints are always satisfied even after deduplication.

Unions, intersections, and discriminated unions

Intersections generate from the first branch (exact intersection generation is not tractable in the general case).

Fallback behavior

Guards that cannot be mapped to a specific arbitrary fall back to fc.anything(). This covers custom guards created with .where(), .and(), lazy guards, and any other guard whose structure is opaque to the generator. These will produce values that may or may not pass the guard; use .arbitrary() and add a .filter(guard) step if you need guaranteed correctness for custom predicates:

Combining with property-based testing

.arbitrary() slots directly into fc.property for full property-based test suites:

Implementation notes

  • fast-check is loaded lazily on the first call to .generate() or .arbitrary(). If it is not installed, a clear error is thrown with installation instructions.
  • The generator reads from guard.meta.jsonSchema, the same accumulated metadata object that drives .toJsonSchema(). Adding a constraint to a guard automatically affects both JSON Schema output and data generation.
  • Constraint chaining composes correctly: is.number.int.positive.lte(100) generates integers in [1, 100] because each helper merges its contribution into the shared metadata object.
  • Dates are clamped to the year range 1000-9000 by default to prevent toISOString() from throwing on extreme values. Explicit .after() or .before() bounds override the defaults.