Zod to TypeScript Type Generator
zod-to-ts generates TypeScript type definitions directly from Zod schemas, converting Zod's runtime validation objects into static TypeScript types. The current stable version is `2.0.0`, with recent releases focusing on supporting Zod v4 and improving the handling of complex type structures, especially recursion. Releases appear to be feature-driven, with new minor versions adding capabilities and major versions introducing breaking changes, particularly around Zod compatibility and internal API improvements. Key differentiators include its ability to generate TypeScript AST nodes directly for programmatic manipulation, robust support for recursive types through an auxiliary type system, and configurable output (e.g., 'input' vs. 'output' types for schemas using transformations or pipes). It also supports JSDoc comments from Zod's `.describe()` method, making generated types more descriptive. This library is crucial for projects aiming to maintain type safety and reduce boilerplate by deriving types directly from Zod validation logic.
Common errors
-
Error: Zod schema version mismatch. `zod-to-ts` v2.x requires Zod v4.x.
cause Attempting to use `zod-to-ts` v2 with an incompatible Zod v3.x installation.fixUpgrade your `zod` package to version 4 or higher: `npm install zod@^4`. -
Error: Cannot represent a Zod schema of type 'ZodTransformer' as a TypeScript type.
cause A `z.transform()` or `z.custom()` Zod schema was encountered without configuring the `unrepresentable` option.fixPass `{ unrepresentable: 'any' }` in the options object to `zodToTs` to allow `any` to be generated for unrepresentable types, or modify your Zod schema to avoid these constructs. -
TypeError: (intermediate value).toArray is not a function
cause Trying to iterate over the `Map.prototype.values()` iterator returned by `auxiliaryTypeStore.definitions.values()` by calling a non-existent `toArray()` method directly.fixUse `Array.from(auxiliaryTypeStore.definitions.values())` to correctly convert the iterator into an array before further processing like `map()`.
Warnings
- breaking Version 2.0.0 of `zod-to-ts` dropped support for Zod v3. Only Zod v4 and newer versions are supported for runtime schema processing.
- breaking The API for overriding types changed in v2.0.0. The `overrides` option is now expected to be a `Map` of Zod types to custom TypeScript nodes, replacing previous object-based configurations.
- gotcha Zod APIs like `z.transform()` and `z.custom()` cannot be accurately represented as static TypeScript types. By default, `zod-to-ts` will throw an error if these are encountered.
- gotcha Recursive Zod schemas (e.g., an object referencing itself) require the `createAuxiliaryTypeStore` and passing an `auxiliaryTypeStore` instance to `zodToTs` to generate correct helper types. Without it, the generated type node might be incomplete or incorrect.
Install
-
npm install zod-to-ts -
yarn add zod-to-ts -
pnpm add zod-to-ts
Imports
- zodToTs
const { zodToTs } = require('zod-to-ts')import { zodToTs } from 'zod-to-ts' - createAuxiliaryTypeStore
const { createAuxiliaryTypeStore } = require('zod-to-ts')import { createAuxiliaryTypeStore } from 'zod-to-ts' - createTypeAlias
const { createTypeAlias } = require('zod-to-ts')import { createTypeAlias } from 'zod-to-ts' - printNode
const { printNode } = require('zod-to-ts')import { printNode } from 'zod-to-ts'
Quickstart
import { z } from 'zod';
import { zodToTs, createAuxiliaryTypeStore, createTypeAlias, printNode } from 'zod-to-ts';
const CategorySchema = z.object({
name: z.string(),
subcategories: z.lazy(() => z.array(CategorySchema)),
});
const UserSchema = z.object({
username: z.string().describe('User\'s unique identifier'),
age: z.number().int().positive(),
roles: z.array(z.literal('admin').or(z.literal('editor')).or(z.literal('viewer'))),
inventory: z.object({
name: z.string().min(1),
itemId: z.number().int().positive(),
quantity: z.number().int().min(0).optional(),
}).array().describe('List of user\'s owned items'),
favoriteCategory: CategorySchema,
});
const auxiliaryTypeStore = createAuxiliaryTypeStore();
const { node: userNode } = zodToTs(UserSchema, { auxiliaryTypeStore });
const userTypeAlias = createTypeAlias(userNode, 'User');
const userTypeString = printNode(userTypeAlias);
console.log('--- User Type ---');
console.log(userTypeString);
console.log('\n--- Auxiliary Types (for recursion) ---');
// Extract and print auxiliary types if any (e.g., for CategorySchema recursion)
const auxiliaryTypePreamble = Array.from(auxiliaryTypeStore.definitions.values())
.map((definition) => printNode(definition.node))
.join('\n');
console.log(auxiliaryTypePreamble);