Zod is a lot better than some of the alternative solutions I've seen. That said, the need for this sort of explicit validation always felt like a failure of where modern web development has taken us. It's so frustrating how full-stack development requires so many ways of describing the same shapes: JS input validation, Swagger for API definition, server-side input validation, ORM for schema conformance, and TypeScrip…
Zod 4
71–80 of 260 posts
Re: Zod 4
#72But how is the below possible - doesn't it need to include most of the TypeScript compiler? Does it compile the type definitions to some kind of validation structure (like how a compiled regex works) and then use just that? - Zero external dependencies - Works in Node.js and all modern browsers - Tiny: 2kb core bundle (gzipped)
Also, the 2kb bundle just for the zod/v4-mini package, the full zod/v4 package is quite large.
Re: Zod 4
#73Re: Zod 4
#74Earlier quoted context omitted.
I think you would use discrimated unions. const MyResult = z.discriminatedUnion("status", [ z.object({ status: z.literal("success"), data: z.string() }), z.object({ status: z.literal("failed"), error: z.string() }), ]); You can define passthrough behavior if there are a bunch of special attributes for a moderator but you don't want to list/check them all. With different methods that have different schema- If they sha…
Hmm, this is pretty interesting, but I still have issues. While Zod seems to be able to transform my server-returned object into a discriminated union, it doesn't seem to be able to tell which of the unions it is. For instance, say that api/user/mod-panel (e.g.) returns only moderator user objects. My API endpoint already knows that it will have moderator-related fields, but Zod forgets that when I parse it.
Here is some pseudocode.
Person = { name: string, height: number }
Animal = {name: string, capability: string}
A = { post: object, methodType: string, person: Person }
ModeratorA = { post: object, moderatorField1: string, moderatorField2: string, person: Person }
UnionA = A && ModeratorA (There's probably a better way of defining A and ModeratorA to share the shared fields)
B = { post: object, animal: Animal }
endpoint person parses UnionA
endpoint animal parses B
You don't put all of your types in one big Union.
Re: Zod 4
#75Earlier quoted context omitted.
The problem with this is that your One True User shape tends to have a bunch of optional properties on it. e.g., in the user profile you fetch Post[], but in the user directory you don't, and so on with other joined properties. If every endpoint returns the One True User, then you end up needing to write conditional logic to guard against (say) `.posts` when you fetch users in the profile, even though you know that `…
In Typescript at least, if the discriminated union is set up correctly, you just need a single check of the type field. That lets TS narrow the type so it knows whether e.g. `.posts` is present or not.
Let's say I have api/profile (which has `.posts`) and api/user-directory (which does not). I define User as a discriminated union - one has type `user-with-posts` and one has type `user-no-posts`. OK, good so far. But now say I have a photo gallery, which returns photos on user. Now I have to add that into my discriminated union type, e.g. `user-with-posts-and-photos`, `user-with-posts-but-not-photos`, `user-with-no-posts-but-yes-photos`... and it gets worse if I also have another page with DMs...
Re: Zod 4
#76Zod 4 looks good but even with their latest improvements, ArkType is still an order of magnitude faster. Sometimes for the sake of backward and syntax compatibility, it is difficult to make something much faster than a fully greenfield newer library. We recently did an analysis of all these types of tools for our project and decided to go with ArkType for partially this reason, the other was TypeScript ergonomics fel…
Re: Zod 4
#77But how is the below possible - doesn't it need to include most of the TypeScript compiler? Does it compile the type definitions to some kind of validation structure (like how a compiled regex works) and then use just that? - Zero external dependencies - Works in Node.js and all modern browsers - Tiny: 2kb core bundle (gzipped)
Re: Zod 4
#78Earlier quoted context omitted.
I think you would use discrimated unions. const MyResult = z.discriminatedUnion("status", [ z.object({ status: z.literal("success"), data: z.string() }), z.object({ status: z.literal("failed"), error: z.string() }), ]); You can define passthrough behavior if there are a bunch of special attributes for a moderator but you don't want to list/check them all. With different methods that have different schema- If they sha…
Hmm, this is pretty interesting, but I still have issues. While Zod seems to be able to transform my server-returned object into a discriminated union, it doesn't seem to be able to tell which of the unions it is. For instance, say that api/user/mod-panel (e.g.) returns only moderator user objects. My API endpoint already knows that it will have moderator-related fields, but Zod forgets that when I parse it.
Re: Zod 4
#79Re: Zod 4
#80Congratulations to the Zod team on the new release. At the risk of sounding overtly negative, I can't help but shudder when I think about the number of breaking changes outlined in the migration guide. For projects that rely heavily on Zod, it feels like a daunting task ahead—one that will demand a lot of developer attention and time to navigate. Having maintained a few frontend projects that are 4-5 years old at wor…
It's honestly been a nightmare, and I wish I had just built in Django instead. The Tailwind 3 -> 4 migration was probably among the most painful, which I was not expecting.