How to Make All Properties Optional in TypeScript (Partial, DeepPartial)
Learn how to make all properties optional in TypeScript using Partial<T>, build a DeepPartial type for nested objects, and know when to use each.
How to Make All Properties Optional in TypeScript (Partial, DeepPartial)#
You've got a User interface with ten required properties. Now you need to write an update function that accepts any subset of those properties maybe you're only updating the user's name, or just their email. You don't want to pass the entire object every time.
This is one of the most common TypeScript questions I see, and the answer is simpler than most people expect. But there's a catch that trips up almost everyone once they start working with nested objects.
What Partial<T> Does#
TypeScript ships with a built-in utility type called Partial<T>. It takes a type and makes every property optional. That's it.
typescriptinterface User { id: number; name: string; email: string; role: "admin" | "user"; createdAt: Date;}// All properties become optionaltype PartialUser = Partial<User>;// equivalent to:// {// id?: number;// name?: string;// email?: string;// role?: "admin" | "user";// createdAt?: Date;// }
The most common use case is update functions. Instead of requiring every field, you accept a Partial of the type:
typescriptasync function updateUser(userId: number, updates: Partial<User>) { // Only the fields the caller passes get updated await db.users.update({ where: { id: userId }, data: updates });}// Now you can update just the nameawait updateUser(1, { name: "New Name" });// Or just the roleawait updateUser(1, { role: "admin" });// TypeScript catches typos and invalid valuesawait updateUser(1, { nmae: "Oops" }); // ❌ Error: 'nmae' does not existawait updateUser(1, { role: "superadmin" }); // ❌ Error: not assignable
Under the hood, Partial is defined as a mapped type it's actually pretty elegant:
typescript// This is the actual definition in TypeScript's libtype Partial<T> = { [P in keyof T]?: T[P];};
It iterates over every key in T and adds a ? to make it optional. Simple, powerful, and built right into the language.
Tip:
Partialpairs well with the spread operator for applying defaults.const config = { ...defaultConfig, ...userConfig }whereuserConfigisPartial<Config>gives you type-safe overrides without requiring every field.
The Problem: Partial Is Only One Level Deep#
Here's where people get burned. Partial<T> only makes the top-level properties optional. If you have nested objects, the inner properties stay required.
typescriptinterface UserProfile { name: string; email: string; address: { street: string; city: string; zip: string; }; preferences: { theme: "light" | "dark"; notifications: boolean; };}type PartialProfile = Partial<UserProfile>;// address?: { street: string; city: string; zip: string }// ^^^^^^ still required!// This is fine:const update1: PartialProfile = { name: "Alice" };// But this fails you can't partially update the address:const update2: PartialProfile = { address: { city: "Portland" }, // ❌ Error: missing 'street' and 'zip'};
If you want to make all properties optional in TypeScript including nested ones you need DeepPartial.
Building a DeepPartial Type#
TypeScript doesn't include DeepPartial out of the box, but building one is only a few lines with a recursive mapped type:
typescripttype DeepPartial<T> = { [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];};
This recursively applies Partial to every level of the object. Now nested updates work:
typescripttype DeepPartialProfile = DeepPartial<UserProfile>;// Partial nested update works perfectlyconst update: DeepPartialProfile = { address: { city: "Portland" }, // ✅ No error preferences: { theme: "dark" }, // ✅ No error};
There's one subtlety worth mentioning. The basic DeepPartial above will also recurse into arrays and other object types, which might not be what you want. A more robust version handles this:
typescripttype DeepPartial<T> = T extends Function ? T : T extends Array<infer U> ? Array<DeepPartial<U>> : T extends object ? { [P in keyof T]?: DeepPartial<T[P]> } : T;
This version leaves functions alone, properly handles arrays, and only recurses into plain objects. If this kind of recursive type gymnastics makes your head spin, that's normal. I've been writing TypeScript for years and I still have to think carefully through conditional types.
If you want to understand the generics patterns behind this, our TypeScript generics guide breaks down <T>, constraints, and conditional types with real-world examples.
Try the JS to TypeScript
Paste your code, get the result instantly. AI-powered, free, no signup.
Open JS to TypeScriptWarning: Don't roll your own
DeepPartialif you're already using a utility library. Both type-fest↗ and ts-toolbelt↗ ship battle-tested versions that handle edge cases you probably haven't thought of.
Quick Comparison: TypeScript Utility Types for Optional Properties#
| Utility Type | What It Does | Built-in? |
|---|---|---|
Partial<T> | Makes all top-level properties optional | Yes |
Required<T> | Makes all top-level properties required (opposite of Partial) | Yes |
Pick<T, K> | Selects specific properties from a type | Yes |
Omit<T, K> | Removes specific properties from a type | Yes |
DeepPartial<T> | Makes ALL properties optional, recursively | No DIY or use type-fest |
These compose nicely together. Need a type with only name and email, both optional? Partial<Pick<User, "name" | "email">>. Need everything except id, all required? Required<Omit<User, "id">>. The combination possibilities are sort of endless but try not to go overboard. If your type expression is longer than the interface it's based on, just write a new interface.
When NOT to Use Partial#
I've seen teams default to Partial everywhere, and it creates a different kind of problem you lose the guarantee that required fields are actually present.
A few places where Partial is the wrong choice:
- API response types. If your API always returns a full user object, type it as
User, notPartial<User>. Otherwise you'll be null-checking every field for no reason. - Form validation output. After validation succeeds, all required fields should be present. Use the full type, not partial.
- Database insert operations. Most ORMs need all required fields for an insert. Use
Partialfor updates, but the full type (orOmit<User, "id">) for inserts.
The right mental model: Partial is for patches situations where you're modifying a subset of an existing record. If you're creating something new, you usually want all the required fields to be required.
mermaidgraph TD A["Do you need all fields?"] -->|Yes| B["Use the full type"] A -->|No| C["Are you updating existing data?"] C -->|Yes| D{"Nested objects?"} C -->|No| E["Use Pick<T, K> for specific fields"] D -->|Shallow only| F["Use Partial<T>"] D -->|Deep nesting| G["Use DeepPartial<T>"]
If you're converting JavaScript code to TypeScript and want proper interfaces generated automatically including the right use of optional vs required properties SnipShift's JS to TypeScript converter↗ infers types from your actual code rather than just slapping any on everything.
For more on choosing between interface and type when defining these structures, check out our interface vs type comparison. And if you want to avoid the most common TypeScript gotchas (including misusing utility types), our common TypeScript mistakes guide is worth a read.
Partial is one of those utility types that seems basic but shows up everywhere once you know it exists. Use it for update DTOs, form state, test fixtures, config overrides anywhere you need flexibility without giving up type safety. And when shallow isn't deep enough, DeepPartial has your back.
Explore more free developer tools at SnipShift.dev↗.
Try the JS to TypeScript
Paste your code, get the result instantly. AI-powered, free, no signup.
Open JS to TypeScript