TypeScriptPick & Omit

Pick & Omit

Pick<T, K> and Omit<T, K> are complementary utility types that let you create new object types by selecting or excluding specific keys from an existing type. They are among the most frequently used tools in any TypeScript codebase, especially when shaping data at API boundaries.

Pick<T, K>

Pick<T, K> creates a new type by keeping only the properties listed in K from type T. K must be a union of keys that exist on T.

TS
interface User {
  id: number;
  name: string;
  email: string;
  passwordHash: string;
  createdAt: Date;
  role: "admin" | "editor" | "viewer";
}

// Only expose what a profile card needs
type UserCard = Pick<User, "id" | "name">;
/*
{
  id: number;
  name: string;
}
*/

// Only expose what a list view needs
type UserListItem = Pick<User, "id" | "name" | "role">;
/*
{
  id: number;
  name: string;
  role: "admin" | "editor" | "viewer";
}
*/
Note
If you specify a key that does not exist on T, TypeScript raises a compile error — Pick is key-safe.
How Pick Is Implemented

Pick is a mapped type that iterates over only the keys listed in K:

TS
// TypeScript's built-in definition
type Pick<T, K extends keyof T> = {
  [P in K]: T[P];
};

// The constraint K extends keyof T guarantees that
// every key in K is a valid key on T.
Omit<T, K>

Omit<T, K> is the inverse: it creates a new type containing every property from T except the ones listed in K.

TS
interface User {
  id: number;
  name: string;
  email: string;
  passwordHash: string;
  createdAt: Date;
  role: "admin" | "editor" | "viewer";
}

// Remove sensitive fields before sending to the client
type PublicUser = Omit<User, "passwordHash">;
/*
{
  id: number;
  name: string;
  email: string;
  createdAt: Date;
  role: "admin" | "editor" | "viewer";
}
*/

// Remove fields that should not be in a create request
type CreateUserInput = Omit<User, "id" | "createdAt" | "passwordHash">;
/*
{
  name: string;
  email: string;
  role: "admin" | "editor" | "viewer";
}
*/
How Omit Is Implemented

TS
// TypeScript's built-in definition (simplified)
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

// It combines Pick and Exclude:
// 1. Exclude<keyof T, K> — remove the unwanted keys from T's key union
// 2. Pick<T, ...>        — keep only the remaining keys
Tip
Note that Omit accepts K extends keyof any (not keyof T), so it does not error if you try to omit a key that does not exist. Pick is stricter on this point.
Pick vs Omit — Choosing Between Them

Use Pick when...

Use Omit when...

The subset is small (2-3 keys)

The subset is large (most keys)

You want to be explicit about what is included

You want to be explicit about what is excluded

The source type is large and you only need a few fields

You need everything except one or two sensitive fields

Creating a narrowly-scoped DTO or view model

Stripping internal / private fields for public APIs

A practical rule of thumb: if you are keeping fewer than half the keys, use Pick. If you are removing fewer keys than you are keeping, use Omit.

API Response Shaping

The most common real-world use of Pick and Omit is controlling what data crosses API boundaries:

TS
interface Order {
  id: string;
  userId: string;
  items: { productId: string; quantity: number; price: number }[];
  total: number;
  status: "pending" | "shipped" | "delivered" | "cancelled";
  internalNotes: string;    // ops-only field
  paymentToken: string;     // never expose to clients
}

// What the client GET /orders/:id response looks like
type OrderResponse = Omit<Order, "internalNotes" | "paymentToken">;

// What the order list endpoint returns (lighter payload)
type OrderSummary = Pick<Order, "id" | "total" | "status">;

function formatOrderResponse(order: Order): OrderResponse {
  const { internalNotes, paymentToken, ...rest } = order;
  return rest;
}

function formatOrderSummary(order: Order): OrderSummary {
  return { id: order.id, total: order.total, status: order.status };
}
Data Transfer Objects (DTOs)

TS
interface Article {
  id: number;
  title: string;
  slug: string;
  body: string;
  authorId: number;
  publishedAt: Date | null;
  createdAt: Date;
  updatedAt: Date;
}

// Create: author provides title, slug, body only
type CreateArticleDTO = Pick<Article, "title" | "slug" | "body">;

// Update: id is required, everything else optional
type UpdateArticleDTO = Pick<Article, "id"> &
  Partial<Pick<Article, "title" | "slug" | "body">>;

// Publish action: just needs the id
type PublishArticleDTO = Pick<Article, "id">;

async function createArticle(dto: CreateArticleDTO): Promise<Article> {
  // fill in id, authorId, timestamps on the server
  return { id: 1, authorId: 42, publishedAt: null, createdAt: new Date(), updatedAt: new Date(), ...dto };
}
Form Types

Pick and Omit are great for deriving form types from domain models, avoiding duplication:

TS
interface Product {
  id: number;
  name: string;
  description: string;
  price: number;
  sku: string;
  createdAt: Date;
}

// Form only collects user-editable fields
type ProductFormValues = Omit<Product, "id" | "createdAt">;

// Confirm that no auto-generated fields appear in the form
const initialValues: ProductFormValues = {
  name: "",
  description: "",
  price: 0,
  sku: "",
};
Pick and Omit vs Intersection Types

You can sometimes achieve similar results with intersection types, but Pick and Omit are usually cleaner and more intentional:

TS
// Intersection approach (verbose, can conflict)
type NameAndEmail = { name: string } & { email: string };

// Pick approach (derives from the source of truth — the User interface)
type NameAndEmailFromUser = Pick<User, "name" | "email">;

// If User changes, Pick<User, ...> stays correct automatically.
// The intersection type would drift out of sync if User types change.

// Intersection is better for ADDING fields:
type UserWithToken = User & { accessToken: string };

// Pick/Omit are better for SUBSETTING or EXCLUDING fields.
Combining Pick and Omit

TS
interface Event {
  id: string;
  title: string;
  description: string;
  startTime: Date;
  endTime: Date;
  location: string;
  organizerId: string;
  capacity: number;
  internalCost: number;   // private financial field
  vendorCode: string;     // private ops field
}

// Public view: no internal fields
type PublicEvent = Omit<Event, "internalCost" | "vendorCode">;

// Calendar tile: only needs summary info
type EventTile = Pick<PublicEvent, "id" | "title" | "startTime" | "endTime">;

// Edit form: omit auto-generated id, keep everything else
type EventFormValues = Omit<PublicEvent, "id">;
Picking from Interfaces vs Type Aliases

Pick and Omit work identically on both interface and type aliases:

TS
// Works with interface
interface Vehicle {
  make: string;
  model: string;
  year: number;
  vin: string;
}
type VehicleCard = Pick<Vehicle, "make" | "model" | "year">;

// Works with type alias
type Point3D = { x: number; y: number; z: number };
type Point2D = Omit<Point3D, "z">;

// Works with generic types
function pickFields<T, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> {
  const result = {} as Pick<T, K>;
  for (const key of keys) {
    result[key] = obj[key];
  }
  return result;
}

const user = { id: 1, name: "Alice", email: "alice@example.com" };
const preview = pickFields(user, ["id", "name"]);
// { id: 1, name: "Alice" }
Warning
Avoid nesting Pick and Omit too deeply — it makes types hard to read. If you find yourself writing Pick<Omit<Pick<T, ...>, ...>, ...>, consider extracting named intermediate types.
Quick Reference

Utility

Syntax

Result

Pick

Pick<User, "id" | "name">

Only id and name from User

Omit

Omit<User, "passwordHash">

User without passwordHash

Combined

Pick<Omit<User, "secret">, "id" | "name">

id and name, secret excluded

With Partial

Partial<Pick<User, "name" | "email">>

Both fields optional

With Required

Required<Omit<UserForm, "id">>

All fields except id are required

Success
Pick is your "whitelist" tool for selecting exactly what you need. Omit is your "blacklist" tool for stripping what you do not want. Together they keep your API surface clean and your types derived from a single source of truth.