Type HTTP PATCH Payload Shapes from JSON
Use json to typescript to model a HTTP PATCH payload — distinguish 'omit field', 'set field to null', and 'update field' in one type.
Detailed Explanation
PATCH Has Three States Per Field
REST PATCH semantics define three operations per field: leave unchanged (omit), clear (set to null), or update (provide value). Partial<T> collapses the second two and loses information.
Example PATCH JSON
{
"title": "New title",
"scheduled_at": null
}
The intent is: change the title, clear the scheduled_at, and leave every other field alone.
A Patch Mapped Type
type Patch<T> = {
[K in keyof T]?: T[K] extends null | undefined ? T[K] : T[K] | null;
};
interface Post {
id: number;
title: string;
body: string;
scheduled_at: string;
published: boolean;
}
type PostPatch = Patch<Omit<Post, "id">>;
// {
// title?: string | null;
// body?: string | null;
// scheduled_at?: string | null;
// published?: boolean | null;
// }
Three-State Handling on the Server
function applyPatch(post: Post, patch: PostPatch): Post {
const next = { ...post };
for (const key of Object.keys(patch) as (keyof PostPatch)[]) {
const value = patch[key];
if (value === null) {
// Clear field — set to null in DB if column is nullable, else default
(next as any)[key] = null;
} else if (value !== undefined) {
// Update field
(next as any)[key] = value;
}
// value === undefined: leave unchanged
}
return next;
}
Why Not Partial<T>?
type WrongPatch = Partial<Post>;
// title?: string; -- no way to express "clear"
Partial<T> lets you omit a field, but does not let you express "explicitly clear it." For PATCH semantics that mean clearing, this matters: a missing field and a null field have different effects.
When to Use This Shape
- REST PATCH endpoints where omission and null are distinct operations.
- JSON Merge Patch (RFC 7396) compatibility.
- Form submissions where users clear fields by emptying them.
- Optimistic UI updates that need to round-trip the user's "clear" intent.
When Not to Apply It
- For PUT endpoints (full replacement), use the base type or
Required<T>. - For partial creation forms (where missing means "use default"),
Partial<T>is enough.
A purpose-built Patch<T> keeps your update API expressive and prevents the common bug of treating omitted fields as clear-instructions.
Use Case
Implementing a PATCH endpoint for a blog post where users can clear the scheduled publish date by setting it to null, while leaving every other field untouched.
Try It — JSON to TypeScript
Related Topics
Apply Partial, Required, and Readonly to JSON-Generated Types
TypeScript Patterns
Decide Optional vs Required Fields in JSON-to-TypeScript
TypeScript Patterns
Apply DeepReadonly to JSON-Generated TypeScript Types
TypeScript Patterns
Type ISO Date Strings vs Plain Strings in JSON-to-TypeScript
TypeScript Patterns
Generate Literal Status Unions from JSON for State Machines
TypeScript Patterns