Since recent typescript features have made it more possible, I’m less interested in runtime validation, and really only keen in build-type schema validation.
There’s a few tools out there that generate code that typescript will prove will validate your schema. That I think is the path forward.
Using a library like zod requires you to trust that Zod will correctly validate the type. Instead, I much prefer to have schema validation code that typescript proves will work correctly. I want the build-type checks that my runtime validation is correct.
Typia generates runtime code that typescript can check correctly validates a given schema https://typia.io/docs/validators/assert/ . I've never actually used it, but this is closer to the realm I prefer.
Using a library like zod requires you to trust that Zod will correctly validate the type.
Not sure I understand this -- are you assuming there’s an existing schema, either a TS type or maybe something else like JSON Schema, and you’re trying to ensure a separate Zod schema parses it correctly?
The usual way to use Zod (or Valibot, etc) is to have the Zod schema be the single source of truth; your TS types are derived from it via z.infer<typeof schema>. That way, there’s no need to take anything on trust, it just works.
The thing that makes libraries like Zod trustworthy is that they:
- parse as their validation mechanism
- compose small units (close to the type system’s own semantics for their runtime equivalents, trivially verifiable), with general composition semantics (also close to the type system), into larger structures which are (almost) tautologically correct.
Obviously there’s always room for some error, but the approach is about as close to “safe” as you can get without a prover. The most common source of error isn’t mistakes in the underlying implementation but mistakes in communicating/comprehending nuances of the semantics (especially where concepts like optionality and strictness meet concepts like unions and intersections, which are also footguns in the type system).
Previously (~2-3 years ago), it was impossible to narrow `unknown` to a fully typed object. Recently-ish, they added the ability for `"foo" in obj` to type-refine `object` to `object & {"foo": unknown}`, which lets you further narrow foo down to something more specific.
I don’t know too much about about the TS ecosystem but do these new systems you talk about do it via a “Smart Constructor”? That is the pattern I typically use to solve this problem in Haskell and Rust code.
There’s a few tools out there that generate code that typescript will prove will validate your schema. That I think is the path forward.