Type Inference and Static Types
How each validation library relates to its language's static type system.
Zod
Infers a fully static TypeScript type directly from the schema (z.infer<typeof schema>), so the schema is the single source of truth for both runtime validation and compile-time types.
Valibot
Also infers static TypeScript types from the schema, matching Zod’s type-inference model while keeping the underlying implementation more modular.
ArkType
Infers static types directly from its type-like string syntax, arguably the tightest coupling between validation and TypeScript’s own type system of any library here.
Joi
Has no built-in static type inference — TypeScript types must be written and maintained separately (or generated by a third-party tool), since Joi predates TypeScript-first schema design.
Pydantic
Uses Python’s own type hints as the schema, so static type checkers (mypy, Pyright) understand model fields directly without a separate inference step.
Marshmallow
Has no built-in connection to Python’s static type hints — schema fields and type annotations are maintained separately unless using third-party extensions.
Hibernate Validator (Bean Validation)
Validation constraints are just annotations on already statically-typed Java fields, so there’s no separate “inference” step — the type system and the validation layer were never separate to begin with.
FluentValidation
Validates already statically-typed C# model classes; there’s no schema-to-type inference step since the model’s types are defined independently in C# first.
go-playground/validator
Validates already statically-typed Go structs via reflection; like Bean Validation, there’s no separate inference step since the struct’s fields are already statically typed.
Garde
Validates already statically-typed Rust structs; the derive macro generates validation code at compile time but doesn’t change or infer the struct’s own field types.
Active Model Validations (Ruby on Rails)
No static type inference, consistent with Ruby’s dynamic typing — validation rules and attribute types are both resolved at runtime.
Laravel Validator
No static type inference, consistent with PHP’s traditionally dynamic style, though validated data can be cast to typed DTOs afterward if desired.