Coding Simplified With Shad

Coding Simplified With Shad

TIL: Difference between Omit and Exclude in TypeScript

TIL: Difference between Omit and Exclude in TypeScript

Listen to this article

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.

Interested in reading more such articles from Mohd Shad Mirza?

Support the author by donating an amount of your choice.

 
Share this