How to enforce function arguments based on complex types in a record constant

30 views Asked by At

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.

0

There are 0 answers