I think I'm missing something with the way more complex conditional type constraints work in Typescript. I'm looking to have a function that restricts me to referencing objects in a constant where the constant is a record of String -> my complex type.
Here's the underlying type:
export type HomogeneousCollection = {
schema: z.ZodType<any>;
type: "homogeneous";
};
export type HeterogeneousCollection = {
schemas: Record<string, z.ZodType<any>>;
type: "heterogeneous";
};
export type AnyCollection = HomogeneousCollection | HeterogeneousCollection;
I then define a constant that contains all my collections:
export const AllCollections: Record<string, AnyCollection> = {
collectionA: {
type: "homogenous"
schema: z.object({foo: 1})
},
collectionB: {
type: "heterogeneous";
schemas: {
docA: z.object({bar: 2})
docB: z.object({baz: 3})
}
}
}
So, I'd like to have a function that is passed all the needed information to extract a schema from a particular entry in my object—so either just the collection name (if it's homogenous) or both name and a document otherwise.
f<Schema extends (extract from object based on collection name and potentially document)>(...?): z.infer<Schema>
f("collectionA") // should compile
f("collectionB", {documentName: "docB"} // should compile
f("collectionB") // should fail to compile
I've tried a few different things, both using conditional types and overloading the function signature for f
, but I can't seem to get it to work. What is the proper/simplest way to do this? I'd like to avoid function overloads, because it seems like I'd generally need the implementation function to take overly broad types.