med payloads before they reach business logic.
- Quick CLI converters (
quicktype) excel at legacy JSON migration but struggle with complex discriminated unions and recursive structures.
- The sweet spot for production systems is a hybrid pipeline:
openapi-typescript for contract generation + Zod for runtime validation + CI enforcement.
Core Solution
1. quicktype: CLI-Driven JSON-to-TS Conversion
Best for legacy JSON payloads, mock data, or rapid prototyping. Parses JSON AST and infers union types, optional fields, and naming conventions.
npm install -g quicktype
quicktype sample.json -o generated.ts --just-types --prefer-const
// generated.ts
export interface ApiResponse {
id: string;
user: User;
metadata?: Metadata;
status: "active" | "inactive" | "pending";
}
export interface User {
name: string;
email: string;
}
export interface Metadata {
createdAt: string;
updatedAt: string;
}
2. openapi-typescript: Schema-First Type Generation
Ideal for REST/GraphQL APIs with formal OpenAPI 3.x contracts. Generates strictly typed interfaces directly from openapi.yaml or openapi.json.
npm i -D openapi-typescript
npx openapi-typescript ./api/openapi.yaml -o ./src/types/api.d.ts
// api.d.ts
export interface paths {
"/users/{id}": {
get: {
responses: {
200: {
content: {
"application/json": components["schemas"]["UserResponse"];
};
};
};
};
};
}
export interface components {
schemas: {
UserResponse: {
id: string;
profile: {
displayName: string;
avatarUrl?: string;
};
};
};
}
3. Zod Inference: Runtime Validation + Static Types
Best for full-stack type safety. Defines runtime schemas that double as static type sources, ensuring payload shape matches expectations at execution time.
import { z } from "zod";
const UserSchema = z.object({
id: z.string().uuid(),
profile: z.object({
displayName: z.string().min(1),
avatarUrl: z.string().url().optional(),
}),
status: z.enum(["active", "inactive", "pending"]),
});
// Static type inference
export type User = z.infer<typeof UserSchema>;
// Runtime validation
export function parseUserPayload(raw: unknown): User {
return UserSchema.parse(raw);
}
Architecture Decision Matrix
- Use
openapi-typescript when you control the API contract or consume well-documented third-party APIs.
- Use
Zod when runtime validation is required (e.g., untrusted inputs, microservice boundaries, form handling).
- Use
quicktype for one-off JSON migrations, legacy system integration, or when no schema exists.
- CI/CD Integration: Run generation scripts in pre-commit hooks or CI pipelines. Fail builds if generated types diverge from committed types.
Pitfall Guide
- Union Type Collapse: Auto-generators frequently merge structurally similar objects into
any or overly broad unions instead of discriminated unions. Always verify type or kind discriminators and manually refine unions when needed.
- Optional vs. Nullable Blind Spots: JSON
null and missing keys are distinct. Generators often map both to T | undefined or T | null incorrectly. Explicitly configure --strict-nullable or use Zod's .nullish() to preserve semantic intent.
- Recursive Schema Truncation: Self-referential types (e.g., comment threads, tree structures) cause infinite AST loops or fallback to
any. Use --no-top-level flags or manually annotate recursive interfaces with interface Node { children?: Node[] }.
- Runtime/Static Type Drift: Generating static TS types without runtime validation leaves applications vulnerable to malformed API responses. Static types compile away; always pair them with runtime guards (
Zod, io-ts, or valibot) in production.
- Schema Version Ignorance: Hardcoding generated types without versioning strategies breaks when APIs introduce breaking changes. Namespace generated types by version (
v1.User, v2.User) and implement gradual migration paths.
Deliverables
- 📘 JSON-to-TS Generation Blueprint: Architecture decision flowchart, CI/CD pipeline templates, and tool selection matrix for frontend/backend teams.
- ✅ Pre-Generation Validation Checklist: 12-point audit for schema quality, discriminator consistency, nullable handling, and recursive structure verification.
- ⚙️ Configuration Templates: Production-ready
quicktype.json, openapi-typescript CLI wrappers, and Zod schema-to-type pipeline scripts with TypeScript strict mode enforcement.