TIL: Difference between Omit and Exclude in TypeScript

TIL: Difference between Omit and Exclude in TypeScript

ยท

3 min read

I was trying to use Omit utility type to create a mapped type and it was giving me an error. Please consider the example below.

The Problem

I have a type with union literals like this

type something = 'abc' | 'bcd' | 'cde' | 'def';

I wanted to create a Mapped type like this

type mappedType = {
    [k in something]: string;
}

This is equivalent to

type mappedType = {
  abc: string;
  bcd: string;
  cde: string;
  def: string;
}

This works fine but let's consider if I want to omit one property.

type mappedTypeWithOmit = {
    [k in Omit<something, "def">]: string;
}

The above code doesn't work. Whereas if I use Exclude instead of Omit, I am able to get the desired result:

type mappedTypeWithExclude = {
    [k in Exclude<something, "def">]: string;
}

This is strange. I went ahead to check Omit declaration in the typescript repo and saw that it uses Exclude under the hood.

/**
 * 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>>;

Click to see code in typescript repo

The error I was getting was not helpful either.

Type 'Omit<something, "def">' is not assignable to type 'string | number | symbol'.
  Type 'Omit<something, "def">' is not assignable to type 'string'.

You can also check this in TypeScript Playground

Let's look at what I was doing wrong.

Omit is used on interface or object type and we are trying to use it on union string literal. That's why the error.

Usage:

type mappedType = {
  abc: string;
  bcd: string;
  cde: string;
  def: string;
}

type mappedTypeWithOmit = Omit<mappedType,'def'>

This will be equivalent to

type mappedTypeWithOmit = {
  abc: string;
  bcd: string;
  cde: string;
}

Exclude is different, it is used to exclude a union type.

Usage:

type something = 'abc' | 'bcd' | 'cde' | 'def';
type somethingWithExclude = Exlude<something, "def">

This will be equivalent to

type somethingWithExclude = 'abc' | 'bcd' | 'cde';

Now we can go ahead and use this to create a mapped type.

type mappedTypeWithExclude ={
  [k in somethingWithExclude]: string;
}

And it will be equivalent to

type mappedTypeWithExclude = {
  abc: string;
  bcd: string;
  cde: string;
}

Tada ๐ŸŽ‰

Takeaway

  • Omit utility type works on object type or interfaces to omit one of the key-value pair.
  • Exclude only works on union literal to exclude one of the property.
  • Omit uses Pick and Exclude under the hook.

Further Reading

I hope this helps the next time you're using Omit or Exclude.

Did you find this article valuable?

Support Shad Mirza by becoming a sponsor. Any amount is appreciated!