[Zod] Dates generated as z.string().date() instead of z.date()
Description
I am using the Zod and Date transformer but I noticed the Zod creates dates as z.string().date() instead of z.date() which messes with the Date transformer. Is there any way to configure Zod to know that there is a date transformer and so that is should use z.date()
Reproducible example or configuration
https://stackblitz.com/edit/hey-api-client-fetch-example
Add "zod" to the above example
OpenAPI specification (optional)
No response
System information (optional)
No response
Hey! Not at the moment, will have to be added
@mrlubos do you have a recommended approach for this? Maybe another transformer? Depending on the lift and with some guidance I could help make a PR for this
I'd need to look into it. These transformer related issues aren't straightforward because transformers don't always work. Assuming that's not an issue for you, this gets easier. You'll still want to know if a field was transformed and selectively apply the other Zod type. I believe there's an opposite problem too, if you're making a request, that's not handled by a transformer. So your mileage may vary!
Are there any updates on this?
The discrepancy between the types and the Zod schemas when the Date Transformer is activated is a major problem when implementing my use cases.
I would suggest the following strategy:
With Date Transformer enabled: z.coerce.date()
With Date Transformer disabled: z.string().date()
What do you think?
I would be happy to support you with the implementation!
I'm facing this too, in my openapi-ts.config.ts I have date transformers enabled, so in my request schema properties I have
expires_at:
format: date
type:
- string
- 'null'
which gives me a type of:
export type CreateInventoryLotRequest = {
lot_number?: string;
expires_at?: Date | null;
lot_count: number;
};
but a zod schema of:
export const zCreateInventoryLotRequest = z.object({
lot_number: z.string().min(0).max(50).optional(),
expires_at: z.union([z.string().date(), z.null()]).optional(),
lot_count: z.number().int().gte(0),
});
Because of this instead of directly using zCreateInventoryLotRequest in my form validator, I need to do something like this because the z.date() vs z.string().date() makes the generated zod schema hard to use with date-pickers that provide dates. I'd need to convert to date string onChange and then convert back to date when passed to the value.
zCreateInventoryLotRequest.merge(
z.object({
expires_at: z.date().nullable().optional(),
}),
)
With Date Transformer enabled: z.string().date() With Date Transformer disabled: z.coerce.date()
Shouldn't it be the opposite? If date transformers are enabled any interaction with the client should use Date and not string?
@petercinibulk @kevinkasper give this a try and let me know how far you get with it! https://github.com/hey-api/openapi-ts/issues/2933#issuecomment-3523551813
@mrlubos Works like a charm, thank you very much!