After version 3.5, TypeScript added an omit < T, k > type.
Omit < T, k > types can exclude some attributes from inherited object attributes.
type User = { id: string; name: string; email: string; }; type UserWithoutEmail = Omit<User, "email">; // Equivalent to type UserWithoutEmail = { id: string; name: string; };
Omit < T, k > in lib es5. d. TS file is defined as follows:
Construct a type with T attribute other than type K
/** * 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>>;
Explain this type definition clearly and understand its principle. We can try to implement our own version to restore its functions.
Define omit < T, k > help type
type User = { id: string; name: string; email: string; };
First, we need to traverse the property names in the User {type. We can use the {keyof} operator to obtain a string set containing all object attributes:
type UserKeys = keyof User; // Equivalent to type UserKeys = "id" | "name" | "email";
Then you need to take out some properties from the string collection.
In the | User | type, you need to remove "email" from "Id" | name "| email". You can use exclude < T, u > to do this:
type UserKeysWithoutEmail = Exclude<UserKeys, "email">; // Equivalent to type UserKeysWithoutEmail = Exclude<"id" | "name" | "email", "email">; // Equivalent to type UserKeysWithoutEmail = "id" | "name";
Exclude < T, u > in lib es5. d. TS file is defined as follows:
/** * Exclude from T those types that are assignable to U */ type Exclude<T, U> = T extends U ? never : T;
It uses a condition type and a {never} type. Use | exclude < T, u > to remove those types that match the type of "email" from the set "Id" | name "| email". The only thing that matches the "email" type is itself, so there is only "id" | "name".
Finally, we need to create an object type that contains a subset of User # type attributes. Specifically, to create an object that only contains UserKeysWithoutEmail type, you can use {pick < T, k > to pick out the corresponding attribute name in the User type.
type UserWithoutEmail = Pick<User, UserKeysWithoutEmail>; // Equivalent to type UserWithoutEmail = Pick<User, "id" | "name">; // Equivalent to type UserWithoutEmail = { id: string; name: string; };
Pick < T, k > in lib es5. d. This is defined in the TS file
/** * From T, pick a set of properties whose keys are in the union K */ type Pick<T, K extends keyof T> = { [P in K]: T[P]; };
Pick < T, k > is a mapping type, which uses the # keyof # operator and an index type # T[P] to obtain the attribute # P in the type object type # t #.
Now, let's integrate the above mentioned , keyof, exclude < T, u > and , pick < T, k > into one type
type UserWithoutEmail = Pick<User, Exclude<keyof User, "email">>;
It is worth noting that this writing can only be applied to the User type we define. Adding a template can make it used elsewhere
type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;
Now, you can calculate the user without email type
type UserWithoutEmail = Omit<User, "email">;
Because the key of an object can only be a string, a number or a Symbol, we can add a constraint to K
type Omit<T, K extends string | number | symbol> = Pick<T, Exclude<keyof T, K>>;
In this way, it seems a little verbose to directly restrict the extension string | number | symbol. We can use , keyof any , because they are equivalent
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
This implements lib es5. d. Types of omit < T, k > defined in TS
/** * 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>>;
Disassemble omit < user, "email" >
The following code is the type of "omit < user," email "> disassembled step by step. Try to follow each step and understand how TypeScript calculates the final type
type User = { id: string; name: string; email: string; }; type UserWithoutEmail = Omit<User, "email">; // Equivalent to type UserWithoutEmail = Pick<User, Exclude<keyof User, "email">>; // Equivalent to type UserWithoutEmail = Pick<User, Exclude<"id" | "name" | "email", "email">>; // Equivalent to type UserWithoutEmail = Pick< User, | ("id" extends "email" ? never : "id") | ("name" extends "email" ? never : "name") | ("email" extends "email" ? never : "email") >; // Equivalent to type UserWithoutEmail = Pick<User, "id" | "name" | never>; // Equivalent to type UserWithoutEmail = Pick<User, "id" | "name">; // Equivalent to type UserWithoutEmail = { [P in "id" | "name"]: User[P]; }; // This is equivalent to: type UserWithoutEmail = { id: User["id"]; name: User["name"]; }; // This is equivalent to: type UserWithoutEmail = { id: string; name: string; };
Reference link
The Omit Helper Type in TypeScript
Omit help type in TypeScript