Menu

TypeScript Partial and Required: Examples and Deep Partial

Partial<T> makes every property of T optional, which is exactly the type of an update or patch object. Learn Partial in update functions, why it is shallow, how to write a DeepPartial, the explicit undefined pitfall, and its opposite Required<T>.

This page includes runnable editors - edit, run, and see output instantly.

Partial<T> is a built-in utility type that makes every property of T optional. It is the natural type for an update or patch: the caller sends only the fields that changed.

Partial<User> is { id?: number; name?: string; email?: string }. The compiler still checks the fields you do pass: { nmae: "x" } or { name: 42 } is an error, which is what makes Partial better than a loose object or any parameter.

How Partial Is Defined

Partial is a one-line mapped type in TypeScript's standard library:

type Partial<T> = {
  [P in keyof T]?: T[P];
};

For each key P of T, it declares an optional property with the same type. Because it maps over keyof T, it keeps readonly on properties that had it. Being an ordinary type, it has no runtime effect: the object passed as changes is the same object either way.

Reading from a Partial Gives T | undefined

Every property of a Partial<T> may be missing, so reading one gives the property type plus undefined. The compiler makes you handle the missing case:

{ ...defaults, ...opts } is the usual way to turn a Partial<Options> back into a complete Options: spread the defaults first and let the given values override them.

The Explicit undefined Pitfall

An optional property may be missing, but it may also be present with the value undefined. Object spread copies that undefined over the real value, and the result type does not show it:

This bites when a patch is built from a form or a query string where empty fields become undefined. The exactOptionalPropertyTypes compiler option (not part of strict) makes { name: undefined } a compile error for name?: string unless you write name?: string | undefined, which prevents it at the source.

Partial Is Shallow

Partial only makes the top-level properties optional. A nested object, if you pass it, must be complete:

index.ts(8,3): error TS2741: Property 'tabSize' is missing in type '{ fontSize: number; }' but required in type '{ fontSize: number; tabSize: number; }'.

The editor property is optional, but once present it has type { fontSize: number; tabSize: number }, unchanged. For settings objects, API patches and test fixtures you often want optional properties at every level. That needs a recursive type.

DeepPartial: A Recursive Partial

TypeScript has no built-in deep version, but it is a few lines. Functions and arrays are left as they are, because making array elements optional would allow [undefined]:

The type is recursive; the merge is not. applySettings merges editor by hand because object spread is shallow too. A generic deep merge function exists in libraries such as lodash (merge), and its typing is harder than the type above.

Required: The Opposite of Partial

Required<T> removes the ? from every property. It is defined with the -? modifier, which also removes undefined from each property's type:

The pattern is the same as with Partial, reversed: users of an API pass a loose config, and the code inside works with a Required version where every value is known to exist. The spread has the same hole as the update function above: a caller who passes port: undefined explicitly overwrites the default with undefined, and the compiler accepts it unless exactOptionalPropertyTypes is on. Required is shallow in the same way Partial is.

Making Only Some Properties Optional or Required

Partial and Required apply to every property. To change just a few, split the type with Pick and Omit and put it back together:

type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
type RequiredBy<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;

interface Post {
  id: number;
  title: string;
  body?: string;
}

type NewPost = PartialBy<Post, "id">;      // id optional, title required, body optional
type Published = RequiredBy<Post, "body">; // body now required
TypeEffectDeep?
Partial<T>every property optionalno
Required<T>every property required, undefined removedno
DeepPartial<T> (your own)optional at every levelyes
PartialBy<T, K> (your own)only the keys K optionalno
Readonly<T>every property readonlyno

Frequently Asked Questions

What does Partial do in TypeScript?

Partial<T> creates a type with all the properties of T marked optional. For interface User { name: string; email: string }, Partial<User> is { name?: string; email?: string }, so {}, { name: "Ada" } and a full user are all valid values.

Is Partial deep in TypeScript?

No, Partial only affects the top-level properties. A nested object inside a Partial<T> must still be complete. For a recursive version, write a DeepPartial<T> type that applies itself to object-typed properties.

What is the opposite of Partial in TypeScript?

Required<T>. It removes the ? from every property and also removes undefined from their types, so Required<{ port?: number }> is { port: number }. It is defined as a mapped type with the -? modifier.

How do I make only some properties optional?

Combine Omit, Pick and Partial: type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>. PartialBy<User, "email"> keeps every property as it was, except email, which becomes optional.

Why is a property undefined after merging a Partial update?

Partial<T> allows a property to be present with the value undefined, and object spread copies it: { ...user, ...{ name: undefined } } has name: undefined even though TypeScript types the result as User. Filter out undefined values before merging, or turn on exactOptionalPropertyTypes so an explicit undefined is rejected.

Coddy programming languages illustration

Learn to code with Coddy

GET STARTED