`Omit<T, K>` inner workings
Chapter 3: TypeScript for real-world applications
Chapters - Table of contents
Omit<T, K> return a new type excluding the given K properties of T:
1interface User {
2  id: string
3  firstName: string
4  lastName: string
5}
6
7type UserWithoutLastName = Omit<User, 'lastName'>
8// `UserWithoutLastName` type is 
9// {
10//   id: string
11//   firstName: string
12// }
13
Like Partial<T>, Omit<T, K> is also a Mapped Type, however, a bit more advanced one that combines many other type helpers as follows:
1type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
2
Let's first take a look at the type helpers used by Omit<T, K>:

Pick<T, K> and Exclude<T, U> inner workings

Pick<T, K>

Pick<T, K> is a Mapped Type similar to Partial<T>:
1type Pick<T, K extends keyof T> = {
2    // keep all `T` properties from `K`
3    [P in K]: T[P];
4};
5
6// usage:
7interface User {
8  id: string
9  firstName: string
10  lastName: string
11}
12
13type UserId = Pick<User, 'id'>
14// `UserId` type is `{ id: string }`
15
The main difference with Partial<T> is that Pick<T, K> expect a second K type argument that should extend keys of the first type argument T (K is a constrained type parameter):
1interface User {
2  id: string
3  firstName: string
4  lastName: string
5}
6
7// valid
8type UserLastName = Pick<User, "lastName">;
9
10// ERROR:
11// Type '"zipcode"' does not satisfy the constraint 'keyof User'.ts(2344)
12type UserZipCode = Pick<User, "zipcode">;
13
"Pick" multiple properties from a type
Pick<T, K> can also be used to "pick" multiple properties, as it follows:
Pick<User, "lastName" | "firstName">
"lastName" | "firstName" is a valid subset of keyof User and Pick<T, K> is gonna iterate over those "K values".

Exclude<T, U>

Exclude<T, U> works as it follows:
1Exclude<string | boolean | number, number>
2// removes any `number` from `T`:
3// => string | boolean
4
5Exclude<string | boolean | number, number | boolean>
6// removes any `number` or `boolean` from `T`:
7// => string
8
9Exclude<"id" | "lastName" | "firstName", "id">
10// removes "id" from the given type (literal string union):
11// => "lastName" | "firstName"
12
Let's now take a look at Exclude<T, U> definition:
1type Exclude<T, U> = T extends U ? never : T
2
Exclude<T, U> uses TypeScript Conditional Type, which works as follows:
1type MyConditionalType<SomeType> = SomeType extends OtherType ? TrueType : FalseType;
2
TypeScript Conditional Types are rarely used while working on React applications, it is mostly used in open-source libraries.
So, how Exclude<T, U> works?
1type Exclude<T, U> = T extends U ? never : T
2
Given a T type, if T is a subset of U, discard the type value, otherwise, keep it.
"discard the type value" is achieved by using the never type which is defined as follows:
The never type represents values that are never observed. In a return type, this means that the function throws an exception or terminates the execution of the program.
never also appears when TypeScript determines there’s nothing left in a union.
In short:
1Exclude<"id", "id"> // returns `never`
2
3Exclude<"lastName", "id"> // returns `lastName`
4
When applied to Generic types (here: T), Condition Types are distributive, which mean that the condition is applied to each member of the given union type (T), for example:
1// with Exclude<T, U> defined as:
2
3type Exclude<T, U> = T extends U ? never
4
5// The following:
6
7type WithoutId = Exclude<"id" | "lastName" | "firstName", "id">
8
9// is equivalent to:
10
11type WithoutId = Exclude<"id", "id"> | Exclude<"lastName", "id"> | Exclude<"firstName", "id">
12type WithoutId = never | "lastName" | "firstName"
13// `never` indicates that "id" should be removed from the union type which gives:
14type WithoutId = "lastName" | "firstName"
15
This training won't cover Conditional types in-depth, for more examples please read the official TypeScript guide.

Back to Omit<T, K>

With Omit<T, K> having the following definition:
1type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
2
we can describe it as follows:
Remove a set of properties keys K from a T type
Let's now see how Omit<T ,K> operates step by step on our User example:
1interface User {
2    id: string,
3    firstName: string,
4    lastName: string,
5}
6
7type UserWithoutId = Omit<User, "id">
8
9// Omit<T, K> with T = User and K = "id"
10
11// T = User and K = "id"
12type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
13
14// is equivalent to:
15type Omit<User, "id"> = Pick<User, Exclude<"id" | "firstName" | "lastName", "id">>;
16
17// once Exclude<T, U> resolved to "firstName" | "lastName", we get:
18
19type Omit<User, "id"> = Pick<User, "firstName" | "lastName">;
20
21// Pick, a Mapped Type, iterates over "firstName" | "lastName" to produce:
22
23// {
24//   firstName: string
25//   lastName: string
26// }
27
By decomposing every step, it is easier to see how the new UserWithoutId is built!

Next

Let's wrap up our Partial<T> and Omit<T, K> deep-dive by looking, step-by-step, how our RegisterUserForm type is built.
We use cookies to collect statistics through Google Analytics.
Do not track
 
Allow cookies