Is it possible for Zod to enforce that a passed schema's type is constrained to a base schema? I suspect I might be way off base here, but hopefully it is clear what I'm trying to achieve in the example.
Thank you.
import { ZodType, z } from "zod";
const baseSchema = z.object({baseString:z.string()})
const validChildSchema = baseSchema.extend({childString:z.string()})
const invalidChildSchema = z.object({childString:z.string()})
class baseClass<TSchema> // eg something like "extends ZodType<typeof baseSchema>"
{}
class childClassValid extends baseClass<typeof validChildSchema>{}
// Can I change the baseclass so that this does not compile?
class childClassInvalid extends baseClass<typeof invalidChildSchema>{}
I think you can achieve something like this by constraining the "output" type of the generic parameter to be a the inferred output type of the base schema.
Eg:
import { z } from "zod";
const baseSchema = z.object({ baseString: z.string() });
const validChildSchema = baseSchema.extend({ childString: z.string() });
const invalidChildSchema = z.object({ childString: z.string() });
class BaseClass<TSchema extends z.ZodType<z.infer<typeof baseSchema>>> {
constructor(public schema: TSchema) {}
}
class ChildClassValid extends BaseClass<typeof validChildSchema> {}
const v = new ChildClassValid(validChildSchema);
const out = v.schema.parse("");
console.log(out.baseString);
console.log(out.childString);
// Property 'baseString' is missing in type '{ childString: string; }' but required in type '{ baseString: string; }'.
class ChildClassInvalid extends BaseClass<typeof invalidChildSchema> {}
Due to Typescripts structural typing, this won't prevent you from using schemas like:
const anotherSchema = z.object({baseString: z.string(), foo: z.number()})
So if that's a concern then you'll need to play around with branded types to simulate nominal typing.