Back to Blog
Lesson 26 of the TypeScript: Typing JavaScript with Confidence course
TypeScriptAugust 13, 20264 min read

Pick and Omit Utilities: Refining Types in TypeScript

Learn how to use Pick and Omit utility types in TypeScript to derive specific object shapes from existing interfaces, streamlining your API request logic.

TypeScriptUtility TypesWeb DevelopmentFrontendAPI
Close-up of a vintage typewriter with the word 'Imprint' on paper, evoking a classic retro feel.

Previously in this course, we explored Mastering the Partial Utility Type in TypeScript for API Updates to handle patch requests. While Partial makes all properties optional, we often need to create types that represent specific subsets of data—like a "Create" payload that excludes an ID, or a "Summary" view that only includes a title and status.

This is where Pick and Omit come in. These utility types allow us to derive new types from existing ones, ensuring our code remains "DRY" (Don't Repeat Yourself) as our application grows.

Why Use Pick and Omit?

In a real-world project, your base Task interface often contains fields generated by the database (like id or createdAt) that shouldn't be sent by the client when creating a new task.

Instead of creating a separate NewTask interface and manually syncing it with your main Task interface, you can derive it. This prevents the "drift" that happens when you update a property in one place but forget to update it in your secondary types.

Using Pick to Extract Properties

The Pick<Type, Keys> utility constructs a type by picking the set of properties Keys from Type. Think of it as a "whitelist" approach.

TYPESCRIPT
interface Task {
  id: string;
  title: string;
  description: string;
  isCompleted: boolean;
  createdAt: Date;
}

// Create a type for the Task Summary view
type TaskSummary = Pick<Task, CE9178">'title' | CE9178">'isCompleted'>;

const mySummary: TaskSummary = {
  title: CE9178">'Learn TypeScript Utilities',
  isCompleted: false
};

Here, TaskSummary only contains title and isCompleted. If you add a new property to Task later, TaskSummary remains untouched, which is exactly what we want for that specific UI component.

Using Omit to Remove Properties

The Omit<Type, Keys> utility constructs a type by picking all properties from Type and then removing Keys. This is a "blacklist" approach, which is often more convenient when you want most of the original interface but need to drop a few specific fields.

In our Task API client, we don't want the user to provide an id or createdAt when creating a task.

TYPESCRIPT
// Create a type for a new task submission(excluding system-generated fields)
type CreateTaskPayload = Omit<Task, CE9178">'id' | CE9178">'createdAt'>;

const newTask: CreateTaskPayload = {
  title: CE9178">'Finish the TypeScript course',
  description: CE9178">'Practice using Pick and Omit.',
  isCompleted: false
};

This is much cleaner than re-typing the entire interface. If you add an updatedAt field to Task, CreateTaskPayload will automatically include it.

Refining API Request Types

Close-up of a laptop keyboard with a note reading 'Coffee Please!' placed on top, suggesting a coffee break.

Let's advance our running project. We have a Task interface, and we need to define types for our API interaction methods.

TYPESCRIPT
// Our base model
interface Task {
  id: string;
  title: string;
  description: string;
  isCompleted: boolean;
  createdAt: Date;
}

// For POST /tasks
type CreateTaskDTO = Omit<Task, CE9178">'id' | CE9178">'createdAt'>;

// For PATCH /tasks/:id(using Partial from our previous lesson)
type UpdateTaskDTO = Partial<Omit<Task, CE9178">'id' | CE9178">'createdAt'>>;

function createTask(task: CreateTaskDTO) {
  // Logic to send task to API
}

By combining Omit and Partial, we've created a robust UpdateTaskDTO that allows users to send just the fields they want to change, while explicitly forbidding them from attempting to modify the id or createdAt timestamps.

Hands-on Exercise

  1. Given the following interface:
    TYPESCRIPT
    interface User {
      id: number;
      username: string;
      email: string;
      isAdmin: boolean;
      lastLogin: Date;
    }
  2. Create a type named UserProfile using Pick that includes only username and email.
  3. Create a type named UserRegistration using Omit that removes id and lastLogin from the User interface.
  4. Verify your work by creating an object of each type.

Common Pitfalls

  • Over-complicating: Don't chain too many utilities together. If you find yourself doing Omit<Pick<...>>, it’s usually a sign that your base interface is doing too much and should be split into smaller, more focused interfaces.
  • Typo sensitivity: Pick and Omit keys are strings. If you misspell a key, TypeScript will throw an error, but it won't always be as helpful as you might expect if you are working with deeply nested types.
  • Ignoring the source: Remember that these utilities are strictly mapping to an existing type. If the underlying interface changes fundamentally, your derived types will change as well—make sure this is the desired behavior!

FAQ

Can I use Pick or Omit with non-object types? No, these utilities only work on object types (like interfaces or type aliases defined as objects).

What happens if I pass a key that doesn't exist? TypeScript will throw a compiler error: Type '...' does not satisfy the constraint 'keyof Type'.

Is it better to use Pick or Omit? Use Pick if the list of keys you want is smaller than the list you don't want. Use Omit if you want most of the properties and only need to drop a few.

Recap

Pick and Omit are essential tools for maintaining type safety while keeping your code clean. They allow you to derive specific interfaces for API requests or UI components directly from your base domain models, preventing redundant code and ensuring that changes to your data structure propagate safely throughout your application.

Up next: We will explore Type Assertions to handle cases where we know more about our data than the TypeScript compiler does.

Similar Posts