engineering

What are Pick and Omit Utility Types in TypeScript?

What are Pick and Omit Utility Types in TypeScript?

Learn how to use TypeScript's Pick and Omit utility types to simplify your code and enhance type safety.

Kaushal Joshi

Kaushal Joshi

Sep 25, 2024 8 min read

TypeScript has skyrocketed in popularity among web developers for its ability to enhance JavaScript with static typing, making large-scale projects more predictable and easier to maintain. The reason it's so popular is that TypeScript helps you catch errors early and provides a toolkit of advanced features to simplify your code.

One such advanced feature is utility types. TypeScript's utility types allow developers to manipulate existing types effortlessly. Two of the most frequently used utility types are Pick and Omit.

In this blog, let’s understand the Pick and Omit utility types in TypeScript — what are they, when to use them, and how to use them.

What Are Utility Types in TypeScript?

Utility types in TypeScript are predefined helper types that enable you to transform and manipulate existing types in a concise and readable manner. They help reduce boilerplate code and allow for cleaner, more reusable type definitions. If you're working with complex interfaces or large data models, utility types like Pick and Omit can make your life significantly easier.

Let's explore these two utility types in detail:

The Pick Utility Type in TypeScript

The Pick utility type is used to create a new type by selecting a subset of properties from an existing type. This can be incredibly useful when working with large interfaces, especially when you only need a few specific properties out of many. The syntax is simple:

Pick<Type, Keys>;
  • Type: The original type from which properties are being selected.
  • Keys: The properties you want to include in your new type, either as a single key or a union of keys.

Example: Extracting specific fields

Suppose you’re working with a User interface that has several properties, but you only need the name and role fields for a certain part of your application. Here’s how you can use Pick:

interface User {
	id: string;
	name: string;
	email: string;
	role: 'user' | 'editor' | 'admin';
	createdAt: Date;
	updatedAt: Date;
}

type UserRole = Pick<User, 'name' | 'role'>;

The newly created UserRole type is a transformation of the User type. Instead of containing all the properties of User, it will only have the name and role fields, looking like this:

{
	name: string;
	role: 'user' | 'editor' | 'admin';
}

By using Pick, you ensure that your new type stays in sync with the original User interface. If role ever changes, your UserRole type will automatically reflect that change, reducing the chances of errors.

Note: The line role: "user" | "editor" | "admin"; defines the role property as a union type, meaning it can only hold one of the specified string values: "user", "editor", or "admin".

This restricts the role to these specific options, ensuring type safety by preventing any value outside of this set from being assigned to role.

Read more about union types in TypeScript here.

Real-world use case of Pick:

Let’s say you're building a dashboard that displays users’ names and roles but not their emails, IDs, or timestamps. Instead of passing the entire User object with unnecessary fields, you can use Pick to streamline the data passed to your component:

function renderUserRole(user: UserRole) {
	console.log(`Name: ${user.name}, Role: ${user.role}`);
}

This makes your code more efficient, ensures you're only passing the data you need, and reduces the risk of handling sensitive or irrelevant information.

Practical applications of Pick:

  • Creating smaller, specialized interfaces: Extract just the fields you need for a specific function or component, helping reduce unnecessary data passing.
  • Enforcing data restrictions: Use Pick to limit the properties of an object when passing it between different parts of your app, ensuring only relevant information is available.

The Omit Utility Type in TypeScript

The Omit type is the opposite of Pick. While Pick selects specific properties, Omit excludes them. It’s useful when you have a large interface but need a version that removes certain fields. This is particularly useful when you want all the properties from a type except for a few. Here’s the syntax:

Omit<Type, Keys>;
  • Type: The original type from which properties are being omitted.
  • Keys: The keys you want to exclude.

Example: Removing fields

Imagine you want to remove the createdAt and updatedAtfields from the User interface. You can do this easily with Omit:

type UserWithoutTimestamps = Omit<User, 'createdAt' | 'updatedAt'>;

The newly created UserWithoutTimestamps type will have all the properties from the original User type, except for createdAt and updatedAt. It will look like this:

{
	id: string;
	name: string;
	email: string;
	role: 'user' | 'editor' | 'admin';
}

Here, we can ensure that properties that are related are excluded and only specified properties are selected. Let's see a real-world use case to understand it better.

Real-world use case

Let’s say you're building a form to update a user’s profile. You don’t want to deal with fields like createdAt and updatedAt that are automatically managed by the system. Using Omit, you can create a cleaner, more focused type for this form, avoiding fields that shouldn't be user-editable:

function updateUserProfile(user: UserWithoutTimestamps) {
	// Update user profile logic here
}

This keeps your type definitions clean and helps prevent accidental modification of system-managed fields.

Practical Applications of Omit:

  • Simplifying interfaces: When you don’t need certain fields in a form or component, Omit helps streamline your types.
  • Adapting types to new requirements: Easily exclude fields that are no longer relevant as your application evolves.

Combining Pick and Omit

You can combine Pick and Omit to create more complex types. This can be particularly useful when you need to modify multiple aspects of a type.

Example: Streamlining complex types

Let's extend the User interface we worked with earlier, and add some more properties:

interface UserProfile {
	id: string;
	name: string;
	age: number;
	email: string;
	address: {
		street: string;
		city: string;
		pincode: number;
		country: string;
	};
	settings: {
		theme: 'light' | 'dark';
		notifications: boolean;
	};
	createdAt: Date;
	updatedAt: Date;
}

Now, let’s say you want a type that includes only the name and email, but also excludes country from the address and notifications from settings. You can combine Pick and Omit like this:

type SimplifiedProfile = Pick<UserProfile, 'name' | 'email'> & {
	address: Omit<UserProfile['address'], 'country'>;
	settings: Omit<UserProfile['settings'], 'notifications'>;
};

The SimplifiedProfile type will look like this:

{
	name: string;
	email: string;
	address: {
		street: string;
		city: string;
	}
	settings: {
		theme: 'light' | 'dark';
	}
}

Let's understand what happens:

  • Firstly, it picks two properties from the root level of UserProfile: name and email.
  • Then, it omits country from a nested property address.
  • And finally, it omits notifications from the other nested property settings, only allowing theme to be selected.

Use cases for combining Pick and Omit

Combining Pick and Omit can be highly effective when you need to tailor existing types for more specific use cases. Here are a few scenarios where this combination shines:

  • Data sanitization for external APIs: When sending data to third-party services, you often want to send only the necessary fields while ensuring sensitive or irrelevant data is excluded. You can Pick the essential fields and Omit the ones you don’t need.
  • Nested structure simplification: In complex data structures, you might want to include certain top-level fields but omit irrelevant nested properties. For instance, when dealing with deeply nested objects, combining Pick to extract the outer fields and Omit to remove unnecessary nested fields ensures you're working with exactly the data you need. (Just like the example we saw above).
  • Custom views or UI components: Imagine a UI component that displays user profiles but doesn’t need administrative or system-level data like timestamps or internal flags. You can Pick user-related fields and Omit system-specific ones to create a clean, focused type for your component.

By combining these utility types, you can precisely define the structure of your types to match the requirements of different parts of your application, making your code both flexible and efficient.

Wrapping Up

TypeScript provides a bunch of utility types that extend the functionality of types and allow you to modify them. We saw two of the most commonly used TypeScript utility types, Pick and Omit. Pick creates a new type by selecting a specific key or a union of keys whereas Omit does exactly the opposite. It creates a new type by excluding certain keys from an existing type.

You can learn more about Utility types in TypeScript in the official documentation.

I hope this guide helps you get more comfortable with TypeScript’s utility types! If you found it useful, feel free to share it with others in the community. I’d also love to know if it helped you. I am most active on Peerlist and Twitter. Feel free to ping me.

And hey, if you're on the lookout for a Frontend Developer Job, check out Peerlist Jobs for some great opportunities.

Until next time, happy typesafing! 👨‍💻

Join Peerlist

or continue with email

By clicking "Join Peerlist“ you agree to our Code of Conduct, Terms of Service and Privacy Policy.