Skip to content

Instantly share code, notes, and snippets.

@dubzzz
Last active December 3, 2025 15:49
Show Gist options
  • Select an option

  • Save dubzzz/2045286b2fe303ed8c94956ea8f0f064 to your computer and use it in GitHub Desktop.

Select an option

Save dubzzz/2045286b2fe303ed8c94956ea8f0f064 to your computer and use it in GitHub Desktop.
Relationship builder in fast-check
import fc from 'fast-check';
type ArbitraryStructure<TSelfParts> = { [K in keyof TSelfParts]: fc.Arbitrary<TSelfParts[K]> };
type ArbitrariesStructure<TAllSelfParts> = { [Name in keyof TAllSelfParts]: ArbitraryStructure<TAllSelfParts[Name]> };
type Arity = '0-1' | '1' | 'many';
type Relationship<TTypeNames> = { arity: Arity; type: TTypeNames };
type SelfRelationshipsToOutput<TRelationships, TAll> = {
[K in keyof TRelationships]: TRelationships[K] extends { arity: '0-1'; type: infer TTypeName extends keyof TAll }
? TAll[TTypeName] | undefined
: TRelationships[K] extends { arity: '1'; type: infer TTypeName extends keyof TAll }
? TAll[TTypeName]
: TRelationships[K] extends { arity: 'many'; type: infer TTypeName extends keyof TAll }
? TAll[TTypeName][]
: never;
};
type Prettify<T> = { [K in keyof T]: T[K] } & {};
type SingleOutput<
TAllSelfParts,
TRelationships extends { [Name in keyof TAllSelfParts]: { [K in string]: Relationship<keyof TAllSelfParts> } },
> = {
[Name in keyof TAllSelfParts]: Prettify<
TAllSelfParts[Name] & SelfRelationshipsToOutput<TRelationships[Name], SingleOutput<TAllSelfParts, TRelationships>>
>;
};
type ExpandOutput<
TAllSelfParts,
TRelationships extends { [Name in keyof TAllSelfParts]: { [K in string]: Relationship<keyof TAllSelfParts> } },
> = {
[Name in keyof SingleOutput<TAllSelfParts, TRelationships>]: SingleOutput<TAllSelfParts, TRelationships>[Name][];
};
declare function rels<
TAllSelfParts,
TRelationships extends { [Name in keyof TAllSelfParts]: { [K in string]: Relationship<keyof TAllSelfParts> } },
>(
arbitraries: ArbitrariesStructure<TAllSelfParts>,
rules: TRelationships,
): Arbitrary<ExpandOutput<TAllSelfParts, TRelationships>>;
const arb = rels(
{
employee: {
name: fc.string(),
},
team: {
name: fc.string(),
},
preference: {},
},
{
employee: {
manager: { arity: '0-1', type: 'employee' },
team: { arity: '1', type: 'team' },
preferences: { arity: 'many', type: 'preference' },
},
team: {},
preference: {},
},
);
fc.property(arb, (v) => {
const name = v.employee[0].name;
const manager = v.employee[0].manager;
const preferences = v.employee[0].preferences;
const team = v.employee[0].team;
const teamName = v.team[0].name;
});
/* Ideally:
const arb = rels({
employee: {
name: fc.string(),
manager: { arity: '0-1', type: 'employee' },
team: { arity: '1', type: 'team' },
preferences: { arity: 'many', type: 'preference', exclusive: true },
},
team: {
name: fc.string(),
},
preference: {},
});*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment