TypeScript & Zod Schema Generator
TalkingSchema's AI copilot generates TypeScript interfaces, Zod validation schemas, and runtime type guards from any ERD. Column types, nullability, enums, check constraints, and default values are all encoded into accurate TypeScript and Zod output — eliminating the manual labor of keeping your database schema and API validation layer in sync.
Outputs are provided as TypeScript code blocks, with an option to download a .ts file coming soon
What Gets Generated
For each table in your ERD, TalkingSchema can produce:
| Output type | Description |
|---|---|
| TypeScript interface (select) | Reflects exactly what the database returns — all columns, nullable where the column is nullable |
| TypeScript interface (insert) | Omits auto-generated fields (id, created_at); marks optional fields with ? |
| Zod schema (insert) | Runtime validation schema for API request bodies — use with Express, Fastify, Hono, tRPC |
| Zod schema (partial update) | .partial() version for PATCH endpoints |
| Zod enum | Maps database enum types to z.enum([...]) |
| Type guard | isX(value: unknown): value is X function for runtime narrowing |
How to Generate
Zod schemas for all tables
Generate Zod validation schemas for every table in this ERD.
Include: insert schema (for POST body validation), select type
(TypeScript interface), and partial schema (for PATCH endpoints).
Export each as named exports.
TypeScript interfaces only
Generate TypeScript interfaces for each table.
- SelectType: all columns, nullable where column is nullable
- InsertType: exclude auto-generated columns (id, created_at, updated_at)
- UpdateType: all non-pk columns as optional
Example Output
Using the Global Sustainable Supply Chain (GSSC) schema:
// types/suppliers.ts
import { z } from "zod";
// --- Enums ---
export const CarbonTierEnum = z.enum(["A", "B", "C", "D"]);
export type CarbonTier = z.infer<typeof CarbonTierEnum>;
// --- Select type (what the database returns) ---
export interface SupplierSelect {
supplier_id: string; // UUID
company_name: string;
country: string;
carbon_tier: CarbonTier;
certification: string | null;
is_active: boolean;
created_at: Date;
updated_at: Date;
}
// --- Zod insert schema (for POST /suppliers request body) ---
export const SupplierInsertSchema = z.object({
company_name: z.string().min(1).max(200),
country: z.string().min(1).max(100),
carbon_tier: CarbonTierEnum,
certification: z.string().max(100).nullable().optional(),
is_active: z.boolean().optional().default(true),
});
export type SupplierInsert = z.infer<typeof SupplierInsertSchema>;
// --- Zod partial schema (for PATCH /suppliers/:id request body) ---
export const SupplierUpdateSchema = SupplierInsertSchema.partial();
export type SupplierUpdate = z.infer<typeof SupplierUpdateSchema>;
// types/products.ts
import { z } from "zod";
import { CarbonTierEnum } from "./suppliers";
export interface ProductSelect {
product_id: string;
sku: string;
name: string;
category: string;
unit_weight_kg: number | null; // DECIMAL maps to number
unit_cost_usd: number;
carbon_intensity_score: number | null;
supplier_id: string;
is_active: boolean;
created_at: Date;
updated_at: Date;
}
export const ProductInsertSchema = z.object({
sku: z.string().min(1).max(50),
name: z.string().min(1).max(200),
category: z.string().min(1).max(100),
unit_weight_kg: z.number().positive().nullable().optional(),
unit_cost_usd: z.number().nonnegative(),
carbon_intensity_score: z.number().min(0).max(999.99).nullable().optional(),
supplier_id: z.string().uuid(),
is_active: z.boolean().optional().default(true),
});
export type ProductInsert = z.infer<typeof ProductInsertSchema>;
export const ProductUpdateSchema = ProductInsertSchema.partial();
// types/orders.ts
import { z } from "zod";
export const OrderStatusEnum = z.enum([
"draft",
"confirmed",
"shipped",
"received",
"cancelled",
]);
export type OrderStatus = z.infer<typeof OrderStatusEnum>;
export const PurchaseOrderInsertSchema = z.object({
supplier_id: z.string().uuid(),
warehouse_id: z.string().uuid(),
order_date: z.coerce.date(),
expected_delivery: z.coerce.date().nullable().optional(),
status: OrderStatusEnum.optional().default("draft"),
});
export type PurchaseOrderInsert = z.infer<typeof PurchaseOrderInsertSchema>;
export const PurchaseOrderItemInsertSchema = z.object({
po_id: z.string().uuid(),
product_id: z.string().uuid(),
quantity: z.number().int().positive(),
unit_cost_usd: z.number().nonnegative(),
});
export type PurchaseOrderItemInsert = z.infer<
typeof PurchaseOrderItemInsertSchema
>;
Customizing the Output
| Requirement | Prompt addition |
|---|---|
camelCase field names | "Use camelCase for all TypeScript property names" |
valibot instead of Zod | "Use valibot syntax instead of Zod" |
| Include discriminated union for status | "Generate a discriminated union type for order status transitions" |
| API response wrapper | "Wrap each select type in a generic ApiResponse<T> wrapper" |
| Strict decimal handling | "Use string instead of number for DECIMAL columns to avoid floating-point precision loss" |
| Separate file per table | "Output each table's types and schemas in its own file" |
Frequently Asked Questions
How are DECIMAL columns handled in TypeScript?
By default, TalkingSchema maps DECIMAL/NUMERIC columns to TypeScript number. If you are handling monetary values or require arbitrary precision, ask the AI to use string instead: "Map all DECIMAL columns to string in TypeScript to avoid floating-point precision issues."
How are enums handled?
Database enum types are mapped to z.enum([...]) with the exact values defined in the schema. The inferred TypeScript type is exported as a union.
Can I get Zod schemas compatible with tRPC?
Yes. Ask: "Generate Zod input schemas formatted for use as tRPC procedure inputs. Use the insert schema for mutations and the UUID schema for queries by ID."
Does this replace a code generator like zod-prisma?
TalkingSchema generates Zod schemas from your ERD model directly — it is not a Prisma plugin. It is most useful for teams not using Prisma, or for generating portable validation schemas that are independent of any ORM.