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
- Utility Types in TypeScript: typescriptlang.org/docs/handbook/utility-ty..
I hope this helps the next time you're using Omit or Exclude.