Generating TypeScript Types from JSON: Schemas, Interfaces & Zod
How to generate type-safe TypeScript interfaces, Zod runtime validation schemas, and JSON Schema definitions from arbitrary JSON payloads.
Generating TypeScript Types from JSON: Schemas, Interfaces & Zod
Consuming untyped JSON from third-party REST APIs or microservices is a primary vector for runtime TypeError: Cannot read properties of undefined in frontend and Node.js applications.
This guide covers modern techniques to transform raw JSON payloads into bulletproof static TypeScript types and runtime Zod validation contracts.
1. The Gap Between Static Types and Runtime Reality
TypeScript interfaces only exist at compile time. Once your code compiles to JavaScript, all interfaces evaporate:
// Compile-time only interface
interface GitHubRepo {
id: number;
name: string;
stargazers_count: number;
}
// Runtime risk: If the API changes or returns null, TypeScript cannot protect you:
const res = await fetch('https://api.github.com/repos/wtool-dev/wtool');
const data = (await res.json()) as GitHubRepo; // Unsafe type assertion!
To achieve true type safety, you need two layers:
- Static Types: For IDE autocomplete and compile-time correctness.
- Runtime Parsers: To validate and parse external JSON payloads at the network boundary.
2. Generating TypeScript Interfaces from JSON
When working with large, deeply nested JSON responses, manually writing TypeScript interfaces is slow and error-prone.
Using the DevFlow JSON to Schema Converter, you can instantly infer full interface trees:
export interface RootObject {
status: string;
data: UserData;
pagination: Pagination;
}
export interface UserData {
userId: string;
email: string;
roles: string[];
preferences: Preferences;
}
export interface Preferences {
theme: 'dark' | 'light' | 'system';
notificationsEnabled: boolean;
}
export interface Pagination {
currentPage: number;
totalPages: number;
totalRecords: number;
}
3. Generating Zod Schemas for Runtime Validation
Zod is the industry standard TypeScript-first schema validation library. By defining a Zod schema, you get both runtime validation and automatic static type inference:
import { z } from 'zod';
export const UserSchema = z.object({
userId: z.string().uuid(),
email: z.string().email(),
roles: z.array(z.string()),
preferences: z.object({
theme: z.enum(['dark', 'light', 'system']),
notificationsEnabled: z.boolean(),
}),
});
// Infer static TypeScript type directly from schema:
export type User = z.infer<typeof UserSchema>;
// Safe runtime parsing:
export function parseUserPayload(rawJson: unknown): User {
const result = UserSchema.safeParse(rawJson);
if (!result.success) {
console.error('Validation error:', result.error.format());
throw new Error('Invalid user payload received');
}
return result.data; // Strongly typed User
}
Generate Zod schemas automatically from raw JSON with our JSON to Zod Converter.
4. Best Practices for API Data Boundaries
- Never cast API responses with
as: Treat all external API inputs asunknownuntil parsed by a validator. - Handle optional vs nullable fields: In JSON, a missing key (
{}) is different from a null value ({"field": null}). Usez.optional()andz.nullable()appropriately. - Use Union Discriminators: For polymorphic JSON payloads (e.g. event streams), use discriminated unions with a common
typeorkindproperty for exhaustive pattern matching.
Interactive Tools for this Guide
Use these free, client-side tools directly in your browser with zero setup or account required: