import { Generator, Arbitrary } from '../Generator' import { Random } from '../Random' import { Shrinkable } from '../Shrinkable' import { shrinkableTuple } from '../shrinker/tuple' /** Helper type to extract the value type `T` from a `Generator`. */ type GenValueType = Gen extends Generator ? T : never /** * Given a tuple of Generators, maps it to a tuple of the corresponding generated value types. * e.g., `[Generator, Generator]` becomes `[A, B]` */ export type GenValueTypes[]> = { [K in keyof Gens]: GenValueType } // Maps a tuple of Generators to a tuple of Shrinkables of their corresponding value types. // e.g., `[Generator, ..., Generator]` becomes `[Shrinkable,...,Shrinkable]` type ShrsFromGens = { [K in keyof Gens]: Shrinkable> } /** * Creates a generator that produces tuples by combining the results of the provided element generators. * The resulting tuple's type is derived from the types generated by the input generators. * * @param elemGens - A rest parameter array of `Generator` instances. * @returns A `Generator` that produces tuples where each element corresponds to the value generated by the respective generator in `elemGens`. * * @example * ```ts * Gen.tuple(Gen.boolean(), Gen.interval(0, 9), Gen.asciiString(0, 4)) * ``` */ export function TupleGen[]>(...elemGens: Gens): Generator> { type Ts = GenValueTypes return new Arbitrary((rand: Random) => { const shrinkables: Shrinkable[] = elemGens.map(elemGen => elemGen.generate(rand)) as ShrsFromGens // The resulting Shrinkable tuple combines the individual shrinkable values. return shrinkableTuple(...shrinkables) as Shrinkable> }) }