Guide
Turning TypeScript types into Zod or Valibot schemas
TypeScript checks your code, not your data. A response from an API, a form submission or a JSON file can contain anything at runtime, and the compiler cannot help. Validation libraries such as Zod and Valibot close the gap, but they need a schema for every type. If the types already exist, writing the schemas again by hand is duplicate work. This converter reads the declarations and writes the schemas.
What is converted
Paste interfaces, type aliases and enums, as many as you like. Interfaces may extend others, and their members may be optional (?) or readonly. Inside types, the converter understands primitives, Date, string and number literals, unions, intersections, arrays in both T[] and Array<T> form, tuples, Record, index signatures, Partial, Required, Pick, Omit, Set and Map. Comments are ignored. Generic declarations and methods are reported and skipped, because a schema describes one concrete shape.
Unions, enums and null
A union of string literals such as 'admin' | 'editor' becomes z.enum(["admin", "editor"]) (or v.picklist in Valibot), which also gives you .options for building select menus. null in a union becomes .nullable() and undefined becomes .optional(). TypeScript enums become an enum of their values: enum Plan { Free = 'free', Pro = 'pro' } turns into z.enum(["free", "pro"]), numeric enums into a union of literals.
Order and recursion
A schema has to exist before another schema uses it, unlike TypeScript types, which can refer to each other in any order. The converter sorts the declarations so dependencies come first. Types that refer to themselves, such as a tree node with children: Node[], keep their TypeScript type for the annotation (z.ZodType<Node>) and use lazy() for the self-reference.
Inferred types and strictness
With “export inferred types” on, each schema is followed by export type User = z.infer<typeof UserSchema> (or v.InferOutput), so you can delete the original declarations and keep a single source of truth. Strict objects reject unknown keys instead of stripping them, which is useful for configuration files where a typo should be an error.
Zod or Valibot
Both validate the same things with similar APIs. Zod has the larger ecosystem and integrations (tRPC, React Hook Form resolvers, OpenAPI generators). Valibot is modular, so bundlers keep only the functions you use, which can make it much smaller in the browser. The converter writes either from the same input.
A worked example
The sample declares User, Address, a Team type built with Pick and a Plan enum. The output defines AddressSchema before UserSchema, writes role: z.enum(["admin", "editor", "viewer"]), turns Team into z.array(UserSchema.pick({ id: true, name: true })), and the enum into z.enum(["free", "pro"]). In Valibot, Team becomes v.array(v.pick(UserSchema, ["id", "name"])).
Adding real constraints
Types say a field is a string; schemas can say much more. After converting, add .email(), .min(1), .max(100), .url() or .regex() where the data has rules, and .default() for values that may be missing.
Where to validate
Validate at the boundaries: when a response arrives from an API, when a form is submitted, when a file or environment variable is read. Inside your own code, the inferred types are enough. safeParse returns a result object instead of throwing, which suits form handling where you want to show every error at once.
Related tools
Generate types and schemas from data instead with JSON to TypeScript, check sample payloads in the JSON Formatter, make Python models with JSON to Pydantic, or test validation patterns in the Regex Tester.
Checked against the current version of the TypeScript to Zod / Valibot on .

