Barakonda
Barakonda2y ago

input using z.or not working properly

i have an input like this let input = z.object({ name: z.string().optional() }).or(z.object({ id: z.number().optional() })); when I call the route with { name: "123" } I get in the input { name: "123" } properly like I should, but when I call the same route with { id: 2 } then I get in the input {} - the rawInput is correctly { id: 2 } but the data is not transferred to input, when I switch the order of the input like this let input = z.object({ id: z.number().optional() }).or(z.object({ name: z.string().optional() })); then now, id is the one that works and name gives {} this is probably a bug, should I post this in the git or maybe it wasn't supposed to work at all?
5 Replies
Nick
Nick2y ago
Think about how it works internally, both properties are optional. It will try to parse each possible type in order, and take the first success as the result. So in both examples, it parses, sees the optional type isn’t there which is fine, and returns the empty result This isn’t exactly a Zod help channel though, you’re best to refer to their own docs and issues for suggestions on workarounds I think there’s an option to make an input with extraneous inputs throw and maybe switching that on will force the wrong type to come up invalid and try the next one
mark salsbery
mark salsbery2y ago
@Barakonda does it work if you remove the optional() calls?
Barakonda
BarakondaOP2y ago
@msalsbery ill check and get back to you soon @Nick Lucas true, but it works if its a sub object inside the main input schema(from another part in my project) like this let input = z.object({ name: z.object({z.string().optional() }).or(z.object({ id: z.number().optional() })); @msalsbery yes' removing the optional works... pretty weird
Nick
Nick2y ago
Your example is incomplete by the way, but I’d guess there’s some non-optional part of the that structure which does match fine You might want a discriminatedUnion
mark salsbery
mark salsbery2y ago
Cool, like @Nick Lucas mentioned, if you think about how it works, with the optional, if the property isn’t there you get the “else” which is {} … the other object definition in the union isn’t looked at