openapi-ts icon indicating copy to clipboard operation
openapi-ts copied to clipboard

[Zod] Dates generated as z.string().date() instead of z.date()

Open petercinibulk opened this issue 8 months ago • 9 comments

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

petercinibulk avatar Apr 02 '25 16:04 petercinibulk

Hey! Not at the moment, will have to be added

mrlubos avatar Apr 02 '25 16:04 mrlubos

@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

petercinibulk avatar Apr 02 '25 17:04 petercinibulk

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!

mrlubos avatar Apr 02 '25 17:04 mrlubos

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!

kevinkasper avatar Jun 02 '25 13:06 kevinkasper

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(),
  }),
)

Redmega avatar Jun 17 '25 20:06 Redmega

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?

Redmega avatar Jun 17 '25 20:06 Redmega

@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 avatar Nov 13 '25 05:11 mrlubos

@mrlubos Works like a charm, thank you very much!

kevinkasper avatar Nov 13 '25 18:11 kevinkasper