Skip to content

Commit

Permalink
✨ Better typings for oneof and frequency (#556)
Browse files Browse the repository at this point in the history
Related to #546
  • Loading branch information
dubzzz authored Mar 2, 2020
1 parent 4c03ea3 commit 80e6d7d
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 11 deletions.
14 changes: 12 additions & 2 deletions src/check/arbitrary/FrequencyArbitrary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,28 @@ class FrequencyArbitrary<T> extends Arbitrary<T> {
}
}

/**
* Infer the type of the Arbitrary produced by oneof
* given the type of the source arbitraries
*/
type FrequencyArbitraryType<Ts extends WeightedArbitrary<unknown>[]> = {
[K in keyof Ts]: Ts[K] extends WeightedArbitrary<infer U> ? U : never
}[number];

/**
* For one of the values generated by `...warbs` - the probability of selecting the ith warb is of `warb[i].weight / sum(warb[j].weight)`
*
* **WARNING**: It expects at least one (Arbitrary, weight)
*
* @param warbs (Arbitrary, weight)s that might be called to produce a value
*/
function frequency<T>(...warbs: WeightedArbitrary<T>[]): Arbitrary<T> {
function frequency<Ts extends WeightedArbitrary<unknown>[]>(...warbs: Ts): Arbitrary<FrequencyArbitraryType<Ts>> {
if (warbs.length === 0) {
throw new Error('fc.frequency expects at least one parameter');
}
return new FrequencyArbitrary([...warbs]);
return new FrequencyArbitrary<FrequencyArbitraryType<Ts>>([...warbs] as WeightedArbitrary<
FrequencyArbitraryType<Ts>
>[]);
}

export { frequency };
12 changes: 10 additions & 2 deletions src/check/arbitrary/OneOfArbitrary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,26 @@ class OneOfArbitrary<T> extends Arbitrary<T> {
}
}

/**
* Infer the type of the Arbitrary produced by oneof
* given the type of the source arbitraries
*/
type OneOfArbitraryType<Ts extends Arbitrary<unknown>[]> = {
[K in keyof Ts]: Ts[K] extends Arbitrary<infer U> ? U : never
}[number];

/**
* For one of the values generated by `...arbs` - with all `...arbs` equiprobable
*
* **WARNING**: It expects at least one arbitrary
*
* @param arbs Arbitraries that might be called to produce a value
*/
function oneof<T>(...arbs: Arbitrary<T>[]): Arbitrary<T> {
function oneof<Ts extends Arbitrary<unknown>[]>(...arbs: Ts): Arbitrary<OneOfArbitraryType<Ts>> {
if (arbs.length === 0) {
throw new Error('fc.oneof expects at least one parameter');
}
return new OneOfArbitrary([...arbs]);
return new OneOfArbitrary<OneOfArbitraryType<Ts>>([...arbs] as Arbitrary<OneOfArbitraryType<Ts>>[]);
}

export { oneof };
9 changes: 2 additions & 7 deletions test/type/index.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,21 +60,16 @@ expectError(fc.tuple(fc.nat(), ''));

// oneof arbitrary
expectType<fc.Arbitrary<string>>(fc.oneof(fc.string(), fc.fullUnicodeString()));
expectType<fc.Arbitrary<number | string>>(fc.oneof(fc.string() as fc.Arbitrary<number | string>, fc.nat()));
expectError(fc.oneof(fc.string(), fc.nat())); // TODO Typings should be improved
expectType<fc.Arbitrary<string | number>>(fc.oneof(fc.string(), fc.nat()));
expectError(fc.oneof(fc.string(), '1'));

// frequency arbitrary
expectType<fc.Arbitrary<string>>(
fc.frequency({ arbitrary: fc.string(), weight: 1 }, { arbitrary: fc.fullUnicodeString(), weight: 1 })
);
expectType<fc.Arbitrary<number | string>>(
fc.frequency(
{ arbitrary: fc.string() as fc.Arbitrary<number | string>, weight: 1 },
{ arbitrary: fc.nat(), weight: 1 }
)
fc.frequency({ arbitrary: fc.string(), weight: 1 }, { arbitrary: fc.nat(), weight: 1 })
);
expectError(fc.frequency({ arbitrary: fc.string(), weight: 1 }, { arbitrary: fc.nat(), weight: 1 })); // TODO Typings should be improved
expectError(fc.frequency({ arbitrary: fc.string(), weight: 1 }, { arbitrary: '1', weight: 1 }));

// option arbitrary
Expand Down

0 comments on commit 80e6d7d

Please sign in to comment.