Benefits of static types in Zod #324
Replies: 3 comments 9 replies
-
For my usage, it's almost entirely the other way around. We define schemas to replace the |
Beta Was this translation helpful? Give feedback.
-
Also, I believe in your example, you could re-write it the other way around to get both safety and ergonomics: const companySizeSchema = z.enum(["1-10", ...]);
type CompanySize = z.infer<typeof companySizeSchema>;
const companySize: { value: CompanySize }[] = companySizeSchema
.options
.map((option: CompanySize) => ({ value: option })); |
Beta Was this translation helpful? Give feedback.
-
I've had some time to think about the idea of Zod-first types and I think I've found a couple of strong counterarguments. If you take the proposed approach of defining validators with Zod and getting TS types for free... 1. Bundle SizeYou'll have so much more runtime artefacts. If you're developing FE app, its bundle size will substantially increase. TS types are compile-time but validators are run-time. Even if treeshaking successfully removes most of them... people often forget about dev mode where no treeshaking happens. I don't like my dev bundles being 60-80Mib instead of 20-40. It feels sluggish it breaks the flow and decreases my own performance as a developer. Bundle size will be a problem with this approach for FE apps. 2. Dynamic typesMost of the time Zod schemas can be defined in module space and TS type derivation is natural. Some of the time, hovewer, validators depend on dynamic data. It's common when you have async validators with In such cases it's no longer possible to define schema in module space. Which means the approach fails you – TS types aren't first class objects and you can't return them from a function. Parametric types in TS are incompatible with this idea. And in my code all schemas are defined dynamically to have just a single way of defining them. So while I agree to the idea that sometimes, for some projects the approach of |
Beta Was this translation helpful? Give feedback.
-
I'd like to say first that this library is truly a piece of art in API design.
Many kudos and tons of respect to the author.
I'd like to question, hovewer, the benefit/drawback ratio for TS types derived from validators.
A typical use of Zod schema after the declaration is to pass it to the form hook:
And that is the end of
schema
. It does not affect the returnedform
in any visible way. And so it doesn't matter ifZodSomething
is an opaque or an obscure type.I have an extensive experience with Zod (1,2,3). I use the strictest TS setups in my projects. I've implemented my own Formik-like library which depends on Zod. Given all that, I can't tell a single moment when I relied on Zod types being super-strict and transparent below
useForm
invocation.Dare one say extreme type-safety may hinder more than help. A typical example:
I can't pass values to
Z.enum
because it expects literal to derive "truly type-safe" tuple.I can't put a literal there because of DRY. Validators mimic and repeat UI values more often than not...
typeof companySize
is never really used anywhere on the client side.So all that magically complex type machinery serves... no purpose outside of Zod and even obfuscates client code 🤷
To not overestimate my personal experience, I'd like to hear from people who use Zod.
Does your code benefit from calculated/derived static types and how exactly?
Beta Was this translation helpful? Give feedback.
All reactions