Apply Partial, Required, and Readonly to JSON-Generated Types
Use json to typescript with mapped types — derive Partial, Required, and Readonly variants from a single base interface for create/update/store layers.
Detailed Explanation
One JSON Sample, Many Variants
A typical CRUD endpoint needs three closely related shapes: the row stored in the database, the input for creation (no id, no timestamps), and the input for partial updates. Mapped utility types derive all three from one source.
Base JSON
{
"id": 7,
"title": "First post",
"body": "Hello world",
"tags": ["intro", "meta"],
"published": true,
"created_at": "2024-03-15T10:30:00Z",
"updated_at": "2024-03-15T10:30:00Z"
}
Generated Base Type
interface Post {
id: number;
title: string;
body: string;
tags: string[];
published: boolean;
created_at: string;
updated_at: string;
}
Three Variants from One Source
// Stored row — readonly so domain code never mutates it
type StoredPost = Readonly<Post>;
// Create payload — server fills id and timestamps
type CreatePost = Omit<Post, "id" | "created_at" | "updated_at">;
// Update payload — every field optional except id
type UpdatePost = { id: number } & Partial<Omit<Post, "id" | "created_at" | "updated_at">>;
Why Derive Instead of Duplicate
If you wrote three independent interfaces, adding a category field to Post would silently leave CreatePost and UpdatePost out of date. With derivation, the new field flows automatically — and if you wanted to exclude it from updates, you would adjust the Omit clause in one place.
When Partial Goes Wrong
Partial<T> makes every field optional and undefined-able. If your update endpoint distinguishes "unset" (null) from "leave alone" (omitted), use a custom mapped type:
type Patch<T> = { [K in keyof T]?: T[K] | null };
This makes every property either omitted, the original type, or explicit null — matching JSON Patch and HTTP PATCH semantics.
Generation Tip
Have your JSON-to-TS converter emit only the base Post interface, then add the derived types by hand. Mapped utilities are short, easy to review, and impossible for a generator to infer without explicit hints about which fields are server-managed.
Use Case
Modeling a blog post with a single Post interface and deriving CreatePost, UpdatePost, and StoredPost variants so adding a new field never requires touching three places.
Try It — JSON to TypeScript
Related Topics
Use Pick and Omit to Narrow JSON-Generated Types
TypeScript Patterns
Apply DeepReadonly to JSON-Generated TypeScript Types
TypeScript Patterns
Use TypeScript Utility Types with JSON-Generated Interfaces
Complex Types
Decide Optional vs Required Fields in JSON-to-TypeScript
TypeScript Patterns
Type HTTP PATCH Payload Shapes from JSON
TypeScript Patterns