Partial Utility Type in TypeScript

Partial<T> makes every property of a type optional. Use it to describe update payloads, configuration overrides, and any object where only some fields change.

6 min read

The TypeScript Partial utility type takes an object type and makes every property optional. You pass it a type, and it returns a new type where none of the fields are required. It is the built-in way to say "this object might have any subset of these properties."

The most common use is typing an update function. You have a User type with many required fields. When a user edits their profile, they might only change their email. Partial&lt;User&gt; describes exactly that: an object that looks like User, but where every field is optional.

typescripttypescript
interface User {
  name: string;
  email: string;
  age: number;
}
 
function updateUser(user: User, fields: Partial<User>) {
  return { ...user, ...fields };
}

The fields parameter accepts any subset of User properties. You can pass only the fields that changed and skip the rest. Here is a call that only updates the email:

typescripttypescript
const original = { name: "Ada", email: "ada@example.com", age: 30 };
const result = updateUser(original, { email: "new@example.com" });
 
console.log(result);
 
// Output:
// { name: "Ada", email: "new@example.com", age: 30 }

The second argument only provides email. The other properties stay as they were. Without Partial&lt;User&gt;, the compiler would demand that you pass name and age too, even though the update logic does not need them.

What Partial produces

Partial&lt;T&gt; adds a question mark to every property in T. The transformation is straightforward: each field that was required becomes optional.

typescripttypescript
interface Product {
  title: string;
  price: number;
  inStock: boolean;
}
 
type PartialProduct = Partial<Product>;

After this transformation, PartialProduct is equivalent to writing { title?: string; price?: number; inStock?: boolean } by hand. Every property is now optional.

This means you can pass an object with any subset of Product fields, including an empty object. The compiler will not complain about missing properties. It also means undefined is a valid value.

If you need to distinguish between "not provided" and "explicitly set to undefined", Partial alone is not enough. You would need a different type for that distinction.

Using Partial for configuration defaults

Another strong use case is configuration objects. Define a full AppConfig type that lists every setting, then let callers pass a Partial&lt;AppConfig&gt; to override only the values they care about.

typescripttypescript
interface AppConfig {
  theme: string;
  fontSize: number;
  showSidebar: boolean;
}
 
const defaults: AppConfig = {
  theme: "light",
  fontSize: 16,
  showSidebar: true,
};

The defaults object represents the full configuration with every field filled in. A setup function accepts a Partial version of AppConfig and spreads the overrides on top of those defaults, so only the fields a caller provides get changed.

typescripttypescript
function initApp(overrides: Partial<AppConfig>) {
  const config = { ...defaults, ...overrides };
  console.log(config);
}
 
initApp({ theme: "dark" });
 
// Output:
// { theme: "dark", fontSize: 16, showSidebar: true }

The caller only specifies the theme. Everything else falls back to the default. This pattern is common in libraries, frameworks, and any code that accepts user-provided options.

Partial is shallow

Partial only affects the top-level properties. If your type has nested object properties, the nested fields stay required.

typescripttypescript
interface BlogPost {
  title: string;
  author: { name: string; email: string };
}

When you write Partial&lt;BlogPost&gt;, the author property itself becomes optional. But if you do provide an author object, it must still have both name and email. Here is what fails:

typescripttypescript
type PartialPost = Partial<BlogPost>;
 
// Error: 'email' is missing inside author
const post: PartialPost = {
  author: { name: "Ada" },
};
 
// Output:
// Property 'email' is missing in type '{ name: string; }'
// but required in type '{ name: string; email: string; }'.

Partial made author optional, but once you provide it, the nested type is unchanged. If you need every nested property to become optional, you write a recursive mapped type. That is a more advanced pattern covered in mapped types in TypeScript.

Combining Partial with Pick

Sometimes you only want to make specific properties optional, not the entire type. Combine Partial with Pick utility type in TypeScript to target a subset of fields.

typescripttypescript
interface User {
  id: number;
  name: string;
  email: string;
  age: number;
}
 
type EditableUserFields = Partial<Pick<User, "name" | "email">>;

Here Pick&lt;User, "name" | "email"&gt; selects only name and email. Then Partial makes those two fields optional. The id and age fields are excluded entirely from EditableUserFields, so they can never be changed through a function that uses this type.

The spread merge pattern

The spread operator with Partial is a clean way to produce an updated object. The original stays unchanged, and the function returns a new object:

typescripttypescript
function edit<T>(original: T, changes: Partial<T>): T {
  return { ...original, ...changes };
}

The generic T captures the full type of the original. The Partial parameter lets the caller pass only the fields that changed. Here is a call:

typescripttypescript
const todo = { title: "Buy milk", done: false, priority: 2 } as const;
const updated = edit(todo, { done: true });
 
console.log(updated);
 
// Output:
// { title: "Buy milk", done: true, priority: 2 }

The return type is the same as the original, so you get full type safety on the result. No type information is lost.

Common mistakes

Expecting Partial to work deeply. It does not. Nested objects keep their required fields. If you need deeply optional types, write a recursive mapped type or restructure your data to avoid deeply nested updates.

Using Partial when only a few properties should be optional. Not every function that accepts partial data needs the entire type to be optional. If only email is updatable, use { email?: string } directly or Partial&lt;Pick&lt;User, "email"&gt;&gt;. Being precise about which fields are optional makes the intent clearer.

Confusing Partial with a runtime check. Partial is a compile-time type. It does not validate the shape of data at runtime. If you receive data from an API, you still need runtime validation in TypeScript to verify the actual values.

Rune AI

Rune AI

Key Insights

⚠ This article has a formatting issue and may not display correctly.

Our team has been notified. The content is shown as plain text below.

- Partial makes every property in T optional. - It is the standard way to type update payloads and configuration overrides. - Partial is shallow. It does not make nested object properties optional. - Combine Partial with Pick to make only selected properties optional. - Like all utility types, Partial exists only at compile time.
RunePowered by Rune AI

Frequently Asked Questions

Does Partial work on nested object properties?

No. Partial only makes the top-level properties optional. Nested objects keep their original shape. If you need deep partial behavior, you must write a custom recursive mapped type.

What is the difference between Partial and making properties optional with a question mark?

Writing `{ x?: number }` creates a new type with x optional. Partial takes an existing type and makes all its properties optional at once. Use Partial when you already have the type and need a version where every field is optional.

Can Partial be combined with other utility types?

Yes. You can compose Partial with Pick, Omit, Required, and other utility types. For example, Partial<Pick<User, 'name' | 'email'>> makes only name and email optional.

Conclusion

⚠ This article has a formatting issue and may not display correctly.

Our team has been notified. The content is shown as plain text below.

Partial is the simplest utility type for the most common object pattern: I have a type and I need a version where every property is optional. Use it for update functions, configuration defaults, and any function that accepts a subset of fields. Remember it only goes one level deep. For nested updates, use a union of field paths or a dedicated update type.