Skip to content

Instantly share code, notes, and snippets.

@ssalbdivad
Last active August 21, 2024 17:05
Show Gist options
  • Save ssalbdivad/d60d876ab6486adc97e38e3f6916e93f to your computer and use it in GitHub Desktop.
Save ssalbdivad/d60d876ab6486adc97e38e3f6916e93f to your computer and use it in GitHub Desktop.
ArkType/Zod Comparison

Here's a comparison between how the same simple user definition would be defined using ArkType and Zod:

image

ArkType's definition syntax is more concise (definitions are about 50% shorter on average) as well as making it more visually obvious what the inferred TypeScript type will be. The ability to infer TypeScript definitions directly is the same, but ArkType's syntax is again more concise by allowing you to use typeof on a property of arkUser directly instead of using an extra "infer" helper.

In general, we also have taken significant steps to optimize and clarify our type hints when hovering over validators. For example, in the case above, this is what you see when you mouse over "zodUser":

image

Unfortunately, it encodes lots of redundant information, the meaning of which is not immediately clear (what does z.ZodTypeAny mean and why is it there?).

This is what it looks like when hovering arkUser:

image

Here's a more general summary of the advantages compared to Zod and other similar validators:

  • 1:1 definitions: Because ArkType definitions mirror TypeScript's own syntax, you usually don't even need to hover over your validator to see their type because unless you're using complex runtime only features like morphs, your definition will already look just like the type it will be inferred as, so you don't need to do the extra mental computation of "okay, what type does this leave me with?"

  • Concision: 50% shorter definitions on average

  • Serializability: Because ArkType uses a parsed syntax like TypeScript instead of relying on chained functions, most definitions are directly serializable and could easily be stored in a simple format like JSON. Library authors can also provide ArkType definitions as part of their API, and users can provide type-safe input without having to directly depend on ArkType themselves. Eventually, ArkType could even be used to perform validation across languages (Python, Rust etc.), whereas Zod and other similar validators are tightly coupled to JavaScript.

  • Errors: Error messages are clearer by default, especially for complex cases like unions.

  • Type-safety: As shown, ArkType deeply validates your definitions. It will give you an error if you try to create a type that is unsatisfiable, e.g. by intersecting two objects with incompatible properties. No other validator can do this.

  • Type-system: In addition to performing validation, ArkType is actually a full type system under the hood, meaning that it can not only check if a given value is allowed by a validator, but check if any arbitrary Type is assignable to another. This has lots of potential for advanced scenarios, but the most important implication for most users is that ArkType is able to implicitly make optimizations that other validators cannot. For intance, Zod is currently struggling to find a solution for users to be able to "discriminate" unions, i.e. define a property that all branches must have that will allow the validator to immediately determine which branch to check (colinhacks/zod#2106). Using its deeply computed internal representation of your types, ArkType automatically discriminates all unions by evaluating the most efficient set of properties to check. So not only is the problem solved by ArkType where Zod is struggling, even the solution Zod is trying to make work requires users to manually specify what key to use to discriminate between branches, whereas the problem is completely solved and tested in ArkType without users ever even having to know discriminated unions exist. For instance, given a union like "climate" in this scope:

    image

    ArkType will automatically discriminate by first checking the "color" prop. If it's brown, it knows it's on the "desert" branch. If it's green, it knows it's on the "rainForest" branch. If it's blue, it will discriminate a second time using the "climate" prop. If it's dry, it knows it's on the "sky" branch. If it's wet, it knows it's on the "ocean" branch. All this is done without the user ever having to even know it's happening, but it will significantly speed up validation, especially as unions get larger. As far as I'm aware, it's not possible to represent multi-step discriminations like this in Zod, even manually.

  • Cyclic types and data: ArkType can infer recursive and cyclic types using scopes like the one above. Zod's documentation claims "because of a limitation of TypeScript, their type can't be statically inferred," and requires you to rewrite them manually. It can also validate cyclic data, which will cause an infinite loop in Zod.

  • Perf: Currently, from a performance perspective, ArkType and Zod are similar, but I'm currently working on a PR to implement a JIT compilation strategy that will make ArkType's validation 50-100x faster than Zod and other similar validators.

Despite my obvious bias, given all of those things, I think ArkType has some really clear advantages. That said, I do think Zod is a great tool and was a significant improvement in terms of developer experience and type safety compared to the previous generation of validators like JOI and Yup. If ArkType did not exist I would likely be using it for validation. Here are some other advantages it currently has over ArkType:

  • Documentation: Zod has clear, thorough documentation. We have a few examples, but we're still getting caught up on documenting the vast majority of our features. We plan to release the new docs alongside the perf upgrades in our upcoming 1.0-beta release. This should significantly close the gap in this area.
  • Battle-tested: Zod has been used for many years and is used in production by many large companies. Significant bugs have had time to surface, even if not all have been addressed. ArkType is thoroughly tested, but we still need more time to reach the maturity level and stability Zod has.
  • Stability: ArkType is still in a 1.0-alpha release, meaning some APIs will change before a stable 1.0 version is released. Although a large part of it is stable (e.g. the definition syntax will not change), this still means that you could have to make updates to some of the way certain complex types are defined if you are using advanced features and want to adopt upcoming releases. Zod's already on major version 3 and is stable, so there will be less volatility. ArkType is rapidly moving toward our 1.0-beta and soon a stable 1.0, but we want to make sure we get it right and don't have to release any breaking changes for a long time, so we want more user feedback before freezing our API.
  • Object "generics": Zod offers utilities like ".pick" and ".omit" that mirror existing generics in TypeScript. ArkType has plans to do the same, but in keeping with our 1:1 validation principle, instead of being chained from types, they'd be accessible directly using the same syntax as TypeScript like:
const partialUser = type("Partial<user>")

This work is currently planned, but for now these methods do not exist in ArkType.

On the whole, I think ArkType has a huge amount of upside relative to Zod and similar validators and would highly recommend it for anyone starting a new project or maintaining an existing product that is actively maintained and has more ability to adapt to minor API changes that will occur as ArkType approaches 1.0. It's also great if you need some of the features ArkType offers that are unavailable in Zod like cyclic types and deeply discriminated unions.

On the other hand, if you're using Zod in production and have a large stable set of validators, I'd wait at least until our beta release to begin transitioning so that that process only has to occur once.

I know that was quite a lot of information- sorry if it was overwhelming 😬 Nothing but respect for ColinHacks and Zod!

@o-az
Copy link

o-az commented May 3, 2023

Thank you! Exactly what I was looking for.

Would be great to include a few words on bundle size comparison.

@amritk
Copy link

amritk commented Mar 20, 2024

Here are some benchmarks of anyone is looking

https://moltar.github.io/typescript-runtime-type-benchmarks/

@ssalbdivad
Copy link
Author

@amritk

Me in April 2023:

I'm currently working on a PR to implement a JIT compilation strategy that will make ArkType's validation 50-100x faster than Zod

That branch now:

https://github.com/arktypeio/arktype/tree/2.0 🫠

Will update the benchmarks as soon as that is merged🔜™️

@amritk
Copy link

amritk commented Mar 20, 2024

Sweet!!

@davidcian
Copy link

Great work, hope this project gets far! Currently integrating ArkType to our SaaS, after considering Zod earlier.

@ssalbdivad
Copy link
Author

ssalbdivad commented Jul 15, 2024

@davidcian Thanks 😊

@amtrik You can see the updated benchmarks for 2.0 for LooseAssertion!

https://moltar.github.io/typescript-runtime-type-benchmarks/

I will add the other categories at some point. Unfortunately, the benchmarking library only supports CJS so it requires a custom build.

Check out the new docs for 2.0 as well if you haven't seen them- working on fleshing them out for a big release this month! https://arktype.io

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment