New Jul 28, 2026

The Omit Helper Type in TypeScript

More Front-end Bloggers All from Marius Schulz View The Omit Helper Type in TypeScript on mariusschulz.com

In version 3.5, TypeScript added an Omit<T, K> helper type to the lib.es5.d.ts type definition file that ships as part of the TypeScript compiler. The Omit<T, K> type lets us create an object type that omits specific properties from another object type:

type User = {
  id: string;
  name: string;
  email: string;
};

type UserWithoutEmail = Omit<User, "email">;

// This is equivalent to: type UserWithoutEmail = { id: string; name: string; };

The Omit<T, K> helper type is defined in lib.es5.d.ts like this:

/**
 * Construct a type with the properties of T except for those in type K.
 */
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

To untangle this type definition and understand how it works, let's see how we could've come up with our own version of the Omit<T, K> helper type.

Defining the Omit<T, K> Helper Type

Let's start with the same User type we've seen above:

type User = {
  id: string;
  name: string;
  email: string;
};

First, we need to be able to retrieve all keys of the User type. We can use the keyof operator to retrieve a union of string literal types that contains all property keys of this object type:

type UserKeys = keyof User;

// This is equivalent to: type UserKeys = "id" | "name" | "email";

Next, we need to be able to exclude a specific string literal type from a union of string literal types. In the case of our User type, we want to exclude the type "email" from the union "id" | "name" | "email". We can use the Exclude<T, U> helper type to do that:

type UserKeysWithoutEmail = Exclude<UserKeys, "email">;

// This is equivalent to: type UserKeysWithoutEmail = Exclude<"id" | "name" | "email", "email">;

// This is equivalent to: type UserKeysWithoutEmail = "id" | "name";

The Exclude<T, U> type is defined in lib.es5.d.ts like this:

/**
 * Exclude from T those types that are assignable to U
 */
type Exclude<T, U> = T extends U ? never : T;

It uses a conditional type and the never type. Using the Exclude<T, U> helper type, we're removing those types in our union type "id" | "name" | "email" that are assignable to the "email" type. That is only true for the string literal type "email" itself, so we're left with the union type "id" | "name".

Finally, we need to create an object type that contains only those properties of our User type whose keys are found in the UserKeysWithoutEmail union type. We can use the Pick<T, K> helper type to pick those properties off of our User type:

type UserWithoutEmail = Pick<User, UserKeysWithoutEmail>;

// This is equivalent to: type UserWithoutEmail = Pick<User, "id" | "name">;

// This is equivalent to: type UserWithoutEmail = { id: string; name: string; };

Here's how the Pick<T, K> helper type is defined in lib.es5.d.ts:

/**
 * From T, pick a set of properties whose keys are in the union K
 */
type Pick<T, K extends keyof T> = {
  [P in K]: T[P];
};

The Pick<T, K> type is a mapped type that uses the keyof operator and an indexed access type T[P] to retrieve the type of the property P in the object type T.

Now, let's summarize all the type operations we've performed using keyof, Exclude<T, U>, and Pick<T, K> in a single type:

type UserWithoutEmail = Pick<User, Exclude<keyof User, "email">>;

Notice that this type is specific to our User type. Let's make this a generic type so we can reuse it in other places:

type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;

We can now use this type to compute our UserWithoutEmail type:

type UserWithoutEmail = Omit<User, "email">;

Since object keys can only be strings, numbers, or symbols, we can add a generic constraint to the type parameter K of our Omit<T, K> helper type to only allow types string, number, or symbol for keys:

type Omit<T, K extends string | number | symbol> = Pick<T, Exclude<keyof T, K>>;

The generic constraint extends string | number | symbol is a bit verbose. We can replace the string | number | symbol union type with the keyof any type since the two are equivalent:

type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

And there we go! We've arrived at the exact definition of the Omit<T, K> helper type as it is found in the lib.es5.d.ts type definition file:

/**
 * Construct a type with the properties of T except for those in type K.
 */
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

Unrolling Omit<User, "email">

Here's a step-by-step evaluation of the Omit<User, "email"> type. Try to follow every step to understand how TypeScript is computing the final type:

type User = {
  id: string;
  name: string;
  email: string;
};

type UserWithoutEmail = Omit<User, "email">;

// This is equivalent to: type UserWithoutEmail = Pick<User, Exclude<keyof User, "email">>;

// This is equivalent to: type UserWithoutEmail = Pick<User, Exclude<"id" | "name" | "email", "email">>;

// This is equivalent to: type UserWithoutEmail = Pick< User, | ("id" extends "email" ? never : "id") | ("name" extends "email" ? never : "name") | ("email" extends "email" ? never : "email") >;

// This is equivalent to: type UserWithoutEmail = Pick<User, "id" | "name" | never>;

// This is equivalent to: type UserWithoutEmail = Pick<User, "id" | "name">;

// This is equivalent to: type UserWithoutEmail = { [P in "id" | "name"]: User[P]; };

// This is equivalent to: type UserWithoutEmail = { id: User["id"]; name: User["name"]; };

// This is equivalent to: type UserWithoutEmail = { id: string; name: string; };

Et voilà, our final UserWithoutEmail type.

Scroll to top