[HN Gopher] Zod: TypeScript-first schema validation with static ...
___________________________________________________________________
Zod: TypeScript-first schema validation with static type inference
Author : tosh
Score : 84 points
Date : 2024-10-07 09:18 UTC (2 days ago)
(HTM) web link (zod.dev)
(TXT) w3m dump (zod.dev)
| threatofrain wrote:
| This is just a link to the front page of possibly the #1 most
| popular type validation library in the ecosystem? Anyways, ya'll
| might want to check out up-and-coming Valibot, which has a really
| nice pipe API.
|
| https://valibot.dev
| sergiotapia wrote:
| A whole lot of yapping and ZERO code on the homepage. Authors
| should remove 90% of the stuff on that landing page, jesus!
|
| also since zod is the de facto validation lib, might be worth a
| specific page talking about why this vs zod. even their
| migration from zod page looks nearly identical between the two
| packages.
| petesergeant wrote:
| On the front page there is a prominent section addressing the
| differences from Zod, which appear to be "much better
| performance"
| rjknight wrote:
| Valibot is really nice, particularly for avoiding bundle size
| bloat. Because Zod uses a "fluent builder" API, all of Zod's
| functionality is implemented in classes with many methods.
| Importing something like `z.string` also imports validators to
| check if the string is a UUID, email address, has a minimum or
| maximum length, matches a regex, and so on - even if none of
| those validators are used. Valibot makes these independent
| functions that are composed using the "pipe" function, which
| means that only the functions which are actually used need to
| be included in your JavaScript bundle. Since most apps use only
| a small percentage of the available validators, the bundle size
| reduction can be quite significant relative to Zod.
| crooked-v wrote:
| Valibot also has much, much more efficient type inference,
| which sounds unimportant right up until you have 50 schemas
| referencing each other and all your Typescript stuff slows to a
| molasses crawl.
| zztop44 wrote:
| Agreed. I recently moved a production app from Zod to Valibot
| for exactly this reason. I still slightly prefer Zod's syntax
| but the performance issues were absolutely killing us.
| Timon3 wrote:
| I recently stumbled onto this when looking for alternatives,
| and though it might sound a bit extreme: the style of
| documentation means I'll never consider it for any project.
| It's strange and honestly somehow unnerving to read
| documentation written from a first-person perspective. Is there
| some good reason for this that I'm missing? Or am I just crazy
| and this isn't an issue for anyone else?
| Bjartr wrote:
| I only see second-person "you" and not first-person "I" in
| the linked documentation. Am I missing what you intended to
| point out?
|
| In any case, this might actually be a good use for an LLM to
| post-process it into whatever style you want. I bet there's
| even a browser extension that could do it on-demand and in-
| place.
| Timon3 wrote:
| Really? For example under "Main concepts" on the "Schemas"
| site[0], I see stuff like this:
|
| - I support the creation of schemas for any primitive data
| type.
|
| - Among complex values I support objects, records, arrays,
| tuples as well as various other classes.
|
| - For objects I provide various methods like pick, omit,
| partial and required.
|
| - Beyond primitive and complex values, I also provide
| schema functions for more special cases.
|
| Same for "Mental model", "Pipeline", "Parse data", "Infer
| types", "Methods" and "Issues" - I'll assume the other
| sections also follow this style. That's all not showing up
| for you?
|
| While the LLM suggestion is nice, it's not something I'm
| comfortable with unless hallucinations are incredibly rare.
| Why would I use a library whose documentation I have to
| pass through an unreliable preprocessor to follow a normal
| style?
|
| [0]: https://valibot.dev/guides/schemas/
| prophesi wrote:
| If they're part of Hacktoberfest, editing those pages to
| drop the first person perspective sounds like a pretty
| useful first contribution.
| Timon3 wrote:
| It seems I'm not the first person to make this
| observation: https://github.com/fabian-
| hiller/valibot/issues/687
|
| I honestly don't want my validation library to "tell a
| story" at the expense of documentation clarity. It's
| absolutely fine that this project uses it, I don't want
| to impose my view on them - I guess it's just not the
| validation library for me.
| kaoD wrote:
| > Or am I just crazy and this isn't an issue for anyone else?
|
| Not an issue for me, to be honest. Why does it bother you at
| all?
| Timon3 wrote:
| I'm not exactly sure myself, but every time I open one of
| the pages, I mentally stumble over the formulations. I
| think there are two components:
|
| 1. The biggest part is that I've simply never seen
| documentation written in this style, any mentions of "I" or
| "we" are usually explaining the choices made by the
| author(s). When skimming documentation I pay more attention
| to those parts. Here those parts don't have a comparable
| meaning.
|
| 2. The smaller part is that the writing style reminds me of
| the way brands use mascots with first-person writing to
| advertise to children. There's not really any other
| association I have with this way of writing, and it makes
| me feel like the author either isn't taking the project
| seriously, or me.
|
| I'm not trying to argue that the documentation should be
| understood this way, or that it should be changed - but
| I've stumbled over this multiple times, and can't imagine
| that it's just me.
| skybrian wrote:
| It's a little too cute, but I don't see it as a deciding
| factor on which library to use.
|
| I think a more important issue is that Valibot hasn't reached
| 1.0 yet. But it looks like it's very close.
| kaoD wrote:
| Does/will this correctly handle `| undefined` vs `?`, i.e.
| correct behavior under `exactOptionalPropertyTypes`?
|
| Zod doesn't (yet[0]) and it's been a pain point for me.
|
| [0] https://github.com/colinhacks/zod/issues/635
| x1000 wrote:
| I ran into exactly same pain point which was enough to
| nullify the benefits of using zod at all.
| mightyham wrote:
| I'm currently using valibot and the author's associated modular
| form library in a production app and can vouch that it's been
| very pleasant to work with.
| Eric_WVGG wrote:
| Is Valibot's error handling any good? Zod's is... like
| punishment for a crime I wasn't aware that I had committed.
| hyperbrainer wrote:
| Maybe OP is one of the lucky 10,000. https://xkcd.com/1053/
| diggan wrote:
| As someone who never jumped onto the TypeScript hype-wagon, what
| is this for? Is this something like clojure.spec by for
| TypeScript so you can do runtime validation of data instead of
| compile-time validation?
|
| Basically joi (https://joi.dev/api/?v=17.13.3) but different in
| some way?
| VoidWhisperer wrote:
| Correct on the part of it being a runtime validation of data
| library (I can't as easily speak to whether or not it is
| similar to joi, never used it)
| _fat_santa wrote:
| I think the killer feature of Zod is type inference. Not sure
| if Joi has support for it yet but you can take a zod schema and
| wrap it in `z.infer` to get the typescript type.
|
| Personally I use zod in my API for body validations, it's super
| nice to write the schema then just use `type Body =
| z.infer(schema)` to get the TS type to use inside the code.
| threatofrain wrote:
| That's table stakes for this niche.
| naberhausj wrote:
| I've not used either, but it appears to be similar to JOI, yes.
|
| The main distinction is that ZOD allows you to extract a
| TypeScript type from your schema. This means you get both
| compile-time and run-time type checking.
| valbaca wrote:
| yep.
|
| Typescript is build-time validation, but in the end TS is "just
| JS"
|
| Zod provides runtime validation (and also works well with TS)
| molszanski wrote:
| Deepkit.io has cool validations in runtime based on TS, but
| it is whole another level.
| newaccountman2 wrote:
| > Is this something like clojure.spec by for TypeScript so you
| can do runtime validation of data instead of compile-time
|
| not really "instead", more like "in addition to". Even if your
| code compiles, if you are receiving data, e.g., via API, then
| you need to check that it actually conforms to the type/schema
| you expect. What is run is JS, so it, sadly, won't just
| crash/error if an object that is supposed to be of `type Cat =
| {name: string, ownerId: number}` lacks an `ownerId` at runtime.
|
| Have you used Pydantic in Python? It's like that, but feels
| worse, IMO lol. I say this because Pydantic fits into writing
| Python code much more naturally than writing Zod stuff fits
| into writing TypeScript, IMO.
| vorticalbox wrote:
| At work I have used zod, myzod, joi though I have settled on
| class-validator as it ties in with nestjs really well.
| timpetri wrote:
| Looking around on Twitter and repos in the OSS community, it
| appears that Zod is now almost always favored over yup, despite
| an almost identical API. Curious to hear what people think if
| they've worked with both. We went with Yup early on at my
| company, and now that's what we use for consistency in our
| codebase. I haven't personally found it to be lacking, but some
| of the logic around nulls and undefined always lead me back to
| the docs.
| roessland wrote:
| My company used Yup initially but we moved to Zod to be able to
| infer types from schemas. For example, API response payloads
| are Zod schemas. OpenAPI components are also generated from Zod
| schemas.
|
| There are some performance issues, and WebStorm is struggling,
| which forced me over to VS Code.
|
| But overall pretty happy.
| kabes wrote:
| But Yup also allows to infer types from schemas...
| psadri wrote:
| One thing to note about zod - it clones objects as it validates
| (parses) them. Eg z.array(z.object()) with an array of 10k
| objects will result in 10k cloned objects - slow.
| molszanski wrote:
| I would suggest https://arktype.io/. Much faster on my project
| leontrolski wrote:
| For those of you from a Python background - this is basically
| "Pydantic for Typescript". See also trpc - cross client/server
| typing using zod under the hood - https://trpc.io/
| brap wrote:
| I always found it pretty awkward that you even need libraries
| like this. A limitation of TS I suppose.
| dhruvrajvanshi wrote:
| I wonder about a Typescript with alternate design decisions. The
| type system is cool and you can do a lot of compile time
| metaprogramming. However, when there's a type error in computed
| types, it's a nightmare to visually parse type {
| foo: ... , bar: ..., ... } can't be assigned to type { foo: ...,
| bar: ... }. type { foo: ... bar: ..., ... } is missing the
| following properties from { foo: ..., bar: ..., ... }
|
| Apart from repeating roughly the same type 4 times (which is a UX
| issue that's fixable), debugging computed types requires having a
| typescript interpreter in your head.
|
| I wonder if we had nominal runtime checked types, it could work
| better than the current design in terms of DX. Basically, the :
| Type would always be a runtime checked assertion. Zod certainly
| fills that gap, but it would be nicer to have it baked in.
|
| The type system would not be as powerful, but when I'm writing
| Kotlin, I really don't miss the advanced features of Typescript
| at all. I just define a data class structure and add
| @Serializable to generate conversions from/to JSON.
| rlp wrote:
| This is my exact experience. TypeScript seemed to hit a
| complexity sweet spot about 5 years ago, then they just kept
| adding more obscure stuff to the type system. I find that
| understanding TypeScript compiler errors can be almost as
| difficult as understanding C++ template errors at times.
| phplovesong wrote:
| This. Haxe is a more sane TS alternative in 2024.
| jadbox wrote:
| It's Haxe still been actively developed? I loved it back in
| the day. The blog hasn't had an update in years.
| wrs wrote:
| TypeScript has a crazy powerful type system because it has to
| be able to describe any crazy behavior that was implemented in
| JavaScript. I mean, just take a look at @types/express-serve-
| static-core [0] or @types/lodash [1] to see the lengths TS will
| let you go.
|
| If you write in TS to start with, you can use a more sane
| subset.
|
| [0]
| https://github.com/DefinitelyTyped/DefinitelyTyped/blob/mast...
|
| [1]
| https://github.com/DefinitelyTyped/DefinitelyTyped/blob/mast...
| dhruvrajvanshi wrote:
| Right. I'm aware. My point was that even though the type
| system is powerful, somehow, I'm able to represent everything
| I need to in Kotlin's type system just fine and it feels a
| lot more type safe because it will throw a type error at
| runtime in the right place if I do a bad cast.
|
| Typescript `as Foo` will not do anything at runtime, and it
| will just keep on going, then throw a type error somewhere
| else later (possibly across an async boundary).
|
| You can, in theory use very strong lint rules (disallow `as`
| operator in favour of Zod, disallow postfix ! operator), but
| no actual codebase that I've worked on has these checks. Even
| the ones with the strictest checks enabled have gaps.
|
| Not to mention, there's intentional unsoundness in the type
| system, so even if you wanted, you couldn't really create a
| save subset of TS.
|
| Then there's the issue of reading the library types of some
| generic heavy code. When I "go to definition" in my fastify
| codebase, I see stuff like this
| RouteHandlerMethod<RawServer, RawRequest, RawReply,
| RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider,
| Logger>
|
| Which expands to this export type
| RouteHandlerMethod< RawServer extends RawServerBase =
| RawServerDefault, RawRequest extends
| RawRequestDefaultExpression<RawServer> =
| RawRequestDefaultExpression<RawServer>, RawReply
| extends RawReplyDefaultExpression<RawServer> =
| RawReplyDefaultExpression<RawServer>, RouteGeneric
| extends RouteGenericInterface = RouteGenericInterface,
| ContextConfig = ContextConfigDefault, SchemaCompiler
| extends FastifySchema = FastifySchema, TypeProvider
| extends FastifyTypeProvider = FastifyTypeProviderDefault,
| Logger extends FastifyBaseLogger = FastifyBaseLogger
|
| > = ( this: FastifyInstance<RawServer, RawRequest, RawReply,
| Logger, TypeProvider>, request: FastifyRequest<RouteGeneric,
| RawServer, RawRequest, SchemaCompiler, TypeProvider,
| ContextConfig, Logger>, reply: FastifyReply<RouteGeneric,
| RawServer, RawRequest, RawReply, ContextConfig,
| SchemaCompiler, TypeProvider> // This return type used to be
| a generic type argument. Due to TypeScript's inference of
| return types, this rendered returns unchecked. ) =>
| ResolveFastifyReplyReturnType<TypeProvider, SchemaCompiler,
| RouteGeneric>
|
| Other languages somehow don't need types this complicated and
| they're still safer at runtime :shrug:
| rimunroe wrote:
| > You can, in theory use very strong lint rules (disallow
| `as` operator in favour of Zod, disallow postfix !
| operator), but no actual codebase that I've worked on has
| these checks. Even the ones with the strictest checks
| enabled have gaps.
|
| That's surprising. I've worked on a few codebases with
| reasonably mature TS usage and they've all disallowed
| as/!/any without an explicit comment to disable the rule
| and explain why the use is required there.
| wrs wrote:
| It's apples and oranges. The type system in Kotlin is
| integrated into the language. TypeScript is a preprocessor
| for JavaScript that isn't allowed to change the JavaScript
| language, or have any runtime.
|
| The "as Foo" construct is for you to tell TS that you know
| better than it, or that you deliberately want to bypass the
| type system. You can have a runtime check, but you have to
| write the code yourself (a type predicate), because TS
| doesn't write or change any JavaScript*, it just type-
| checks it.
|
| I've certainly worked in new codebases where a relatively
| simple subset of TS types were used. Even then there were a
| few places the crazy type system was helpful to have. For
| example, we enforced that the names of the properties in
| the global configuration object weren't allowed to have
| consecutive uppercase letters!
|
| (* with minor exceptions like transpiling for new JS
| features)
| spencerchubb wrote:
| Couldn't this be improved by showing a diff between the
| mismatched types?
| dhruvrajvanshi wrote:
| Yes, I did mention that the UX of the type errors could be
| improved and probably should, but once you start getting into
| conditional types, and nested types (which may not be fully
| expanded when you see the error), it gets hairy.
| mhh__ wrote:
| Can you do _any_ compile time metaprogramming in typescript?
| molszanski wrote:
| I very much enjoy more an alternative. Sadly much less hyped
| https://arktype.io/
| threatofrain wrote:
| What do you like most about arktype?
| aleksiy123 wrote:
| Does anyone have a nice combination of tooling for typed handlers
| + client generation.
|
| Thinking maybe Zod + Zod open API.
|
| Really looking to replicate similar spec first workflow similar
| to protobuf services.
|
| https://typespec.io/ also looks promising but seems early.
| bjacobso wrote:
| I think you are looking for https://ts-rest.com/
| kaoD wrote:
| Nice. I'm looking to migrate away from a legacy custom
| framework over Express and this could help.
|
| If someone has tried both, can anyone share how it compares
| with tRPC[0]?
|
| [0] https://trpc.io/
| bjacobso wrote:
| From my understanding trpc is very similar, however, the
| rpc mechanism is not a standard. ts-rest produces openapi
| schemas and speaks REST over http, as well as a typed
| client.
|
| That being said, I am actually slowly migrating off ts-rest
| and adopting @effect/schema and @effect/platform/HttpApi, I
| foresee this being the direction the typescript ecosystem
| heads in over the next few years. However, the APIs are not
| stable yet and it has a bit of a learning curve, so would
| not adopt lightly
| AWebOfBrown wrote:
| I really wanted to adopt tRPC but the deal breaker was it
| being opinionated on status codes without allowing
| configurability. Because I needed to meet an existing API
| spec, that meant ts-rest was a better option. I think
| there's an aditional option with a native spec generator in
| frameworks like Hono, and maybe Elysia.
| mnahkies wrote:
| My tool https://openapi-code-
| generator.nahkies.co.nz/overview/about generates typed handlers
| based around koa (routing, req/res validation using zod) from
| openapi 3, as well as typed clients with optional zod
| validation using fetch/axios.
|
| It also supports typespec using their transpilation to openapi
| 3 tooling
| bearjaws wrote:
| One of the brilliant decisions of the AI SDK from Vercel was to
| use Zod.
|
| It makes tool calling and chaining very robust, despite how
| finicky LLMs can be.
| bjacobso wrote:
| zod is great, but I have been moving to @effect/schema and think
| it deserves a mention here. @effect/schema is the evolution of
| io-ts, which originally inspired zod.
|
| It supports decoding as well as encoding, and fits natively into
| the rest of the effect ecosystem.
|
| https://effect.website/docs/guides/schema/introduction
|
| It does come with the cost of importing effect, so might not be
| the best in certain scenarios. However, there are smaller options
| than zod if that is a concern.
| obeavs wrote:
| Yep. Effect is so cool. The ability encode AND decode is
| tomorrow's standard.
|
| With all the work they're doing on durable workflows, hard to
| imagine that 2025 is anyone else's year.
| dgellow wrote:
| Zod is fantastic, we use it pretty extensively at Stainless.
| Definitely one of my favorite JS library. Not calling it a parser
| combinator was a really good marketing move
| Stoids wrote:
| The fragmentation around runtime validation libraries is pretty
| crazy. The fact that half these comments mention some alternative
| library that mimics almost the exact API of Zod illustrates that.
|
| It is filling a necessary shortcoming in the gradual typing of
| TypeScript, and using validator schema types to power other APIs
| generic inference is powerful. I am optimistic about an obvious
| leader emerging, or at least a better story about swapping
| between them more easily, but a bit annoying when trying to pick
| one to settle on for work that I have confidence in. That being
| said, Zod seems like the community favorite at the moment.
| skybrian wrote:
| Yes, it's annoying. I share your optimism. This is how the
| JavaScript (and now TypeScript) community figures things out.
|
| Note that TypeScript had competitors, too. It got better. Zod
| has an early lead and is good enough in a lot of ways, but I'm
| not sure it will be the one.
|
| Perhaps someday there will be a bun/deno-like platform with
| TypeScript++ that has validation merged in, but it's probably
| good that it's not standardized yet.
| root_axis wrote:
| I prefer typebox because it uses JSON schema. As far I'm aware
| it's otherwise on par with Zod, but I might be unaware of some
| capabilities of Zod that typebox lacks.
| steve_adams_86 wrote:
| I love Zod, but recently I've been converting to Effect's Data
| and Schema modules.
|
| Previously I liked a combination of Zod and ts-pattern to create
| safe, pattern matching-oriented logic around my data. I find
| Effect is designed far better for this, so far. I'm enjoying it a
| lot. The Schema module has a nice convention for expressing
| validators, and it's very composable and flexible:
| https://effect.website/docs/guides/schema/introduction
|
| There are also really nice aspects like the interoperability
| between Schema and Data, allowing you to safely parse data from
| outside your application boundary then perform safe operations
| like exhaustively matching on tagged types (essentially
| discriminated unions): https://effect.website/docs/other/data-
| types/data#is-and-mat...
|
| It feels extremely productive and intuitive once you get the hang
| of it. I didn't expect to like it so much.
|
| I think the real power here is that these modules also have full
| interop with the rest of Effect. Effects are like little lazy
| loaded logical bits that are all consistent in how they resolve,
| making it trivial to compose and execute logic. Data and Schema
| fit into the ecosystem perfectly, making it really easy to
| compose very resilient, scalable, reliable data pipelines for
| example. I'm a convert.
|
| Zod is awesome if you don't want to adopt Effect wholesale,
| though.
| bjacobso wrote:
| I've had a very similar experience, and have been slowly moving
| from zod and ts-rest to @effect/schema and
| @effect/platform/HttpApi as well as migration to Effect Match
| from ts-pattern. There is a learning curve but its a pretty
| incredible ecosystem once you are in it for a bit.
|
| I think the real turning point was typescript 5.5 (May 2024).
| The creator of typescript personally fixed a bug that unlocked
| a more natural generator syntax for Effect, which I think
| unlocks mainstream adoption potential.
|
| https://twitter.com/MichaelArnaldi/status/178506160889445172...
| https://github.com/microsoft/TypeScript/pull/58337
| morbicer wrote:
| I feel like Effect is today's Ramda. So cool but it's going
| to be regretted by you and people coming after you in few
| years. Me and my team reverted to more stupid code and we are
| happier.
| bjacobso wrote:
| that is certainly a possibility
| steve_adams_86 wrote:
| I agree in some contexts. Kind of like Rust, I see a place
| for more durable code that's harder to reason about in some
| cases.
|
| I wouldn't use Effect for a lot of things. For some things,
| I'm very glad to have it. One thing Effect has going for it
| that Ramda didn't is that it's much less abstract and it's
| quite a bit more opinionated about some more complex
| concepts like error handling, concurrency, or scheduling.
|
| Kind of like state machines. You shouldn't use them for
| everything. For some things, it's a bad idea not to (in my
| opinion).
|
| Then of course subjectivity is a factor here. Some people
| will never like conventions like Effect, and that's fine
| too. Just write what feels right.
| steve_adams_86 wrote:
| I agree about the turning point. Things have improved
| dramatically. And I know it probably doesn't feel the same
| for tons of people, but I love to see generators being used
| in every day code.
|
| The learning curve just about turned me away from it at the
| start, but I'm glad I stuck with it.
|
| I think learning Effect would actually teach a lot of people
| some very useful concepts and patterns for programming in
| general. It's very well thought out.
| dimal wrote:
| How did you find learning Effect? The sales pitch sounds
| great, but when I went through the docs it seemed pretty
| confusing to me. I'm sure there are reasons for the
| everything but I couldn't grok it. In particular, I'm
| thinking of the Express integration example.[0] I look at
| that and think, I need all that just to create a server and a
| route? What's the benefit there? I'm hesitant to buy into the
| ecosystem after looking at that. I want to like it, though.
|
| [0] https://effect.website/docs/integrations/express
| theschwa wrote:
| Yeah, looking at that example feels like jumping straight
| into the deep end of the pool. I think it helps going
| through a tutorial that breaks down the why of each piece.
| I really liked this tutorial on it:
| https://www.typeonce.dev/course/effect-beginners-complete-
| ge...
|
| Some core things from Effect though that you can see in
| that Express example:
|
| * Break things down into Services. Effect handles
| dependency injection, that's typed, for services so you can
| easily test them and have different versions running for
| testing, production, etc. * Fibers for threaded execution *
| Managing resources to make sure they're properly closed
| with scope
|
| I think a lot of these things though often aren't truly
| appreciated until you've had something go wrong before or
| you've had to build a system to manage them yourself. *
| dimal wrote:
| Yeah, this looks like the tutorial I needed. Thanks.
| bjacobso wrote:
| I agree, some of there examples are a little overly
| complicated by their quest to be hyper composable. In fact
| they should probably remove that example. I am currently
| using it with Remix, and using their @effect/platform
| package to produce a simple web handler (request: Request)
| => Response (thank remix for heavily promoting the adoption
| of web standards).
|
| I fully agree parts of the ecosystem are complex, and
| likely not fully ready for broad adoption. But I do think
| things will simplify with time, patterns will emerge, and
| it will be seen as react-for-the-backend, the de facto
| first choice. effect + schema + platform + cluster will be
| an extremely compelling stack.
| BenoitP wrote:
| And thus custom validation goes to json, completing a what is old
| is new again cycle. After XML/XSD, after CORBA.
| agluszak wrote:
| Could someone explain to me what problem exactly Zod solves?
|
| Why do you need to do `type User = z.infer<typeof User>;` instead
| of declaring a class with typed fields and, idk, deriving a
| parser for it somehow? (like you would with Serde in Rust for
| example). I don't understand why Zod creates something which
| looks like an orthogonal type hierarchy.
|
| For context: I come from the backend land, I enjoy strong, static
| typing, but I have very little experience with JS/TS and
| structural typing
| xmonkee wrote:
| The User object in your example is used to parse the data. Its
| the "somehow" part of your question. There is no way to go from
| a type to data in typescript (there is no runtime awareness of
| types whatsoever) so zod solves this by you writing the zod
| object and then deriving the type from _it_. Basically you only
| have to weite one thing to get the parser and the type.
| outlore wrote:
| The "type User =" statement creates a TypeScript type from the
| zod schema, which can be useful when passing that definition
| around to functions
|
| The schema object is useful for runtime validation, e.g.
| User.parse(). this is handy when validating payloads that come
| over the wire that might be untrusted. the output of the
| "parse()" function is an object of type User
|
| you can kind of think of it like marshaling Json into a struct
| in Go :)
| _heimdall wrote:
| Zod offers runtime type validation where typescript only does
| this at build time. You can also use it for data normalization,
| safely parsing date strings to Date objects for example.
| cheriot wrote:
| I used it to validate data from config files matched the
| schema. I imagine it could be useful for other sources of
| suppose-to-be-structured data like an http body.
| arzig wrote:
| There's no macro system in TS that could analyze the type to
| build the parser. So, you work the other way and build the
| parser and then produce the type from that.
| tubthumper8 wrote:
| > deriving a parser for it somehow
|
| Serde in Rust does this with the Rust macro system, but
| TypeScript doesn't have a macro system. That's why people have
| to go the other way, the programmer defines the parser, then
| TypeScript can infer the type from the parser.
|
| I have seen a library that invented their own macro system (a
| script that you configure to run before build, and it writes
| code into your node_modules directory), though I can't recall
| the name.
| Cu3PO42 wrote:
| Zod has been a great boon to a project I've been working on. I
| get data from multiple sources where strong types cannot be
| generated and checking the schema of the response has caught a
| great number of errors early.
|
| Another feature that I use intensively is transforming the
| response to parse JSON into more complex data types, e.g. dates
| but also project-specific types. In some situations, I also need
| to serialize these data types back into JSON. This is where Zod
| lacks most for my use-case. I cannot easily specify bidirectional
| transforms, instead I need to define two schemas (one for
| parsing, one for serializing) and only change the transforms. I
| have added type assertions that should catch any mistakes in this
| manual process, but it'd be great if I didn't have to keep these
| two schemas in sync.
|
| Another comment mentioned @effect/schema [0], which apparently
| supports these encode/decode relationships. I'm excited to try it
| out.
|
| [0] https://effect.website/docs/guides/schema/introduction
| n00bskoolbus wrote:
| Something cool that I can't remember if it was posted on HN at
| one point or I stumbled across when looking for alternatives to
| yup but this repo has been compiling a bunch of different
| benchmarks for runtime validation of ts validation libraries.
| Obviously to some degree the performance is arbitrary when you're
| reaching millions of operations per second but on the flipside
| their benchmarks are against rather data. Would be interested to
| see comparison of either more nested data or otherwise complex.
| Maybe something to look at in my spare time.
|
| https://moltar.github.io/typescript-runtime-type-benchmarks/
___________________________________________________________________
(page generated 2024-10-09 23:00 UTC)