Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference b/w only Exclude and Omit (Pick & Exclude) Typescript

Tags:

typescript

As per the definition of the Pick @ typescriptlang.org, it constructs a new type for the mentioned properties only. Exclude @ typescriptlang.org is the opposite of it.

I've seen the following usage

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

But I don't quite get it. We could have simply used Exclude to leave out the non-required fields and constructed a new type of it. Why the combined Pick and Exclude is used as Omit?

Another example:

function removeName<Props extends ExtractName>(   props: Props ): Pick<Props, Exclude<keyof Props, keyof ExtractName>> {   const { name, ...rest } = props;   // do something with name...   return rest; } 

Can't the return type of above be re-written with Exclude as Exclude<Props, ExtractName>?

like image 761
HalfWebDev Avatar asked Jul 06 '19 18:07

HalfWebDev


People also ask

What does Omit type do?

The TypeScript Omit utility type Like the Pick type, the Omit can be used to modify an existing interface or type. However, this one works the other way around. It will remove the fields you defined. We want to remove the id field from our user object when we want to create a user.

What is pick in TypeScript?

Pick<Type, Keys> is a built-in utility type in TypeScript, which constructs a type by picking the set of properties Keys (string literal or union of string literals) from Type . type UserInfo = Pick<User, 'name' | 'age'> Now, the user is UserInfo type, which doesn't have a level property.


1 Answers

You are right about Pick, it takes an object type and extracts the specified properties. So:

 Pick<{ a: string, b:string }, 'a' > === { a: string }  

The opposite of this is actually the later added Omit. This type takes an object type and removes the specified properties from the type.

 Omit<{ a: string, b:string }, 'a' > === { b: string } 

Exclude is a different beast, it takes a union type and removes a constituent of that union.

Exclude<string | number, string > === number 

Exclude is defined as:

type Exclude<T, U> = T extends U ? never : T; 

This means that Exclude will return never if T extends U, and T if it does not. So this means that:

  • Exclude<string, number> is string
  • Exclude<string, string> is never

The thing is that conditional types distribute over naked type parameters. So this means that if applied to a union we get the following:

Exclude<string | number, number>     => Exclude<string, number> | Exclude<number, number> // Exclude distributes over string | number     => string | never => // each application of Exclude resolved to either T or never     => string  // never in unions melts away 

Exclude is used in the definition of Omit. Exclude<keyof T, K> takes a union of the keys of T and removes the keys specified by K. And then Pick extracts the remaining properties from T.

Edit

While both Omit and Exclude take two type arguments (and no relationship is enforced between the two) they can not be use interchangeably. Look at the result of some applications of these types:

type T0 = Omit<{ a: string, b: string }, "a"> //  { b: string; }, a is removed  type T1 = Exclude<{ a: string, b: string }, "a"> // { a: string, b: string }, a does not extend { a: string, b: string } so Exclude does nothing   type T2 = Omit<string | number, string> // Attempts to remove all string keys (basically all keys) from string | number , we get {} type T3 = Exclude<string | number, string> // string extends string so is removed from the union so we get number 
like image 161
Titian Cernicova-Dragomir Avatar answered Sep 27 '22 16:09

Titian Cernicova-Dragomir