The Omit Helper Type in TypeScript

栏目: IT技术 · 发布时间: 4年前

内容简介:In version 3.5, TypeScript added anTheTo untangle this type definition and understand how it works, let's see how we could've come up with our own version of the

In version 3.5, TypeScript added an Omit<T, K> helper type to the lib.es5.d.ts type definition file that ships as part of the TypeScript compiler. The Omit<T, K> type lets us create an object type that omits specific properties from another object type:

type User = {
  id: string;
  name: string;
  email: string;
};

type UserWithoutEmail = Omit<User, "email">;

// This is equivalent to:
type UserWithoutEmail = {
  id: string;
  name: string;
};

The Omit<T, K> helper type is defined in lib.es5.d.ts like this:

/**
 * 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>>;

To untangle this type definition and understand how it works, let's see how we could've come up with our own version of the Omit<T, K> helper type ourselves.

Defining the Omit<T, K> Helper Type

Let's start with the same User type we've seen above:

type User = {
  id: string;
  name: string;
  email: string;
};

First, we need to be able to retrieve all keys of the User type. We can use the keyof operator to retrieve a union ofstring literal types that contains all property keys of this object type:

type UserKeys = keyof User;

// This is equivalent to:
type UserKeys = "id" | "name" | "email";

Next, we need to be able to exclude a specific string literal type from a union of string literal types. In the case of our User type, we want to exclude the type "email" from the union "id" | "name" | "email" . We can use the Exclude<T, U> helper type to do that:

type UserKeysWithoutEmail = Exclude<UserKeys, "email">;

// This is equivalent to:
type UserKeysWithoutEmail = Exclude<
  "id" | "name" | "email",
  "email"
>;

// This is equivalent to:
type UserKeysWithoutEmail = "id" | "name";

The Exclude<T, U> type is defined in lib.es5.d.ts like this:

/**
 * Exclude from T those types that are assignable to U
 */
type Exclude<T, U> = T extends U ? never : T;

It's using aconditional type and the never type . Using the Exclude<T, U> helper type, we're removing those types in our union type "id" | "name" | "email" that are assignable to the "email" type. That is only true for the string literal type "email" itself, so we're left with the union type "id | "name" .

Finally, we need to create an object type that contains a subset of the properties of our User type. Specifically, we want to create an object type that contains only those properties whose keys are found in the UserKeysWithoutEmail union type. We can use the Pick<T, K> helper type to pick those properties off of our User type:

type UserWithoutEmail = Pick<User, UserKeysWithoutEmail>;

// This is equivalent to:
type UserWithoutEmail = Pick<User, "id" | "name">;

// This is equivalent to:
type UserWithoutEmail = {
  id: string;
  name: string;
};

Here's how the Pick<T, K> helper type is defined within lib.es5.d.ts :

/**
 * 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];
};

The Pick<T, K> type is amapped type that's using the keyof operator and anindexed access type T[P] to retrieve the type of the property P in the object type T .

Now, let's summarize all the type operations we've performed using keyof , Exclude<T, U> , and Pick<T, K> in a single type:

type UserWithoutEmail = Pick<User, Exclude<keyof User, "email">>;

Notice that this type is specific to our User type. Let's make this a generic type so we can reuse it in other places:

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

We can now use this type to compute our UserWithoutEmail type:

type UserWithoutEmail = Omit<User, "email">;

Since object keys can only be strings, numbers, or symbols, we can add a generic constraint to the type parameter K of our Omit<T, K> helper type to only allow types string , number , or symbol for keys:

type Omit<T, K extends string | number | symbol> =
  Pick<T, Exclude<keyof T, K>>;

The generic constraint extends string | number | symbol is a bit verbose. We can replace the string | number | symbol union type by the keyof any type since the two are equivalent:

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

And there we go! We've arrived at the exact definition of the Omit<T, K> helper type as it is found within the lib.es5.d.ts type definition file:

/**
 * 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>>;

Unrolling Omit<User, "email">

Here's a step-by-step evaluation of the Omit<User, "email"> type. Try to follow every step to understand how TypeScript is computing the final type:

type User = {
  id: string;
  name: string;
  email: string;
};

type UserWithoutEmail = Omit<User, "email">;

// This is equivalent to:
type UserWithoutEmail = Pick<
  User,
  Exclude<keyof User, "email">
>;

// This is equivalent to:
type UserWithoutEmail = Pick<
  User,
  Exclude<"id" | "name" | "email", "email">
>;

// This is equivalent to:
type UserWithoutEmail = Pick<
  User,
  | ("id" extends "email" ? never : "id")
  | ("name" extends "email" ? never : "name")
  | ("email" extends "email" ? never : "email")
>;

// This is equivalent to:
type UserWithoutEmail = Pick<User, "id" | "name" | never>;

// This is equivalent to:
type UserWithoutEmail = Pick<User, "id" | "name">;

// This is 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;
};

Et voilà, our final UserWithoutEmail type.


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

iBATIS实战

iBATIS实战

(加)Clinton Begin、(加)Brandon Goodin、(加)Larry Meadors / 叶俊 / 人民邮电出版社 / 2008-5 / 45.00元

《图灵程序设计丛书•Java系列•iBATIS in Action iBATIS实战》是讲述iBATIS框架的权威著作。书中既详实地介绍了iBATIS的设计理念和基础知识,也讨论了动态SQL、高速缓存、DAD框架等高级主题,还讲解了iBATIS在实际开发中的应用。《图灵程序设计丛书•Java系列•iBATIS in Action iBATIS实战》的最后给出了一个设计优雅、层次清晰的示例程序JGa......一起来看看 《iBATIS实战》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

SHA 加密
SHA 加密

SHA 加密工具