blog icon indicating copy to clipboard operation
blog copied to clipboard

TypeScript的一些小用法 - 预定义的有条件类型

Open ly2011 opened this issue 6 years ago • 0 comments

TypeScript的一些小用法 - 预定义的有条件类型

预先定义的条件类型(Predefined conditional types)

TS提供了几种内置的预定义的条件类型:

  • Exclude<T, U> -- 从 T 中剔除可以复制给 U 的类型。
  • Extract<T, U> -- 提取 T 中可以赋值给 U 的类型。
  • NonNullable<T> -- 从 T 中剔除 nullundefined
  • ReturnType<T> -- 获取函数返回值类型。
  • InstanceType<T> -- 获取构造函数类型的实例类型。

下面分别来举例:

1. Exclude

type T00 = Exclude<"a" | "b" | "c" | "d", "a" | "c" | "f">; // "b" | "d"
const str0: T00 = "d";

在这个例子中,因为用到了 Exclude 这个条件类型,会尝试寻找在 T 类型中有,但在 U 类型中没有的成员,最后将获取到的Union类型"b"|"d"赋给T100。

2. Extract

type T01 = Extract<"a" | "b" | "c" | "d", "a" | "c" | "f">; // "a" | "c"
const str01: T01 = "a"

Extract首先是提取出的意思,应用 Extract 条件类型,会尝试寻找T类型成员和U类型成员的交集,在该示例中,提取的是 "a"|"c"。

3. NonNullable

type T04 = NonNullable<string | number | undefined>; // string | number
const str04: T04 = 123

通过运行 NonNullable, 清除了 undefined 类型成员。

4. ReturnType

type T10 = ReturnType<() => string>; // string
type T11 = ReturnType<(s: string) => void>; // void

通过 ReturnType, 返回了泛型参数T的返回值类型。

5. InstanceType

class C {
  x = 0;
  y = 0;
}
type T20 = InstanceType<typeof C>; // C

Omit

目前的ts版本(3.2及以前)并没有内置Omit,那么Omit是什么呢?开始我对这个Omit也很好奇,在很多开源的实现里都能看到它的身影。Omit本身有省略和删除的意思,那在ts里这个Omit也很有可能有着相似的操作。查了一些资料之后,学习到,Omit确实是用来删除指定成员。ts虽然没有原生内置Omit,但却可以通过其他内置类型进行实现,比如:

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

搭配Pick这个映射类型,就可以实现 Omit 的效果,我们一点点来拆分这个类型实现。

首先看等号的右侧,Pick是一个ts内置的映射类型,Pick的实现为:

type Pick<T, K extends keyof T> = {
  [P in K]: T[P]
}

首先这个 "K extends keyof T" 说明这个类型值必须为T类型属性的子集,也就是说假如有一个 interface 定义如下:

interface Student {
  name: string;
  age: number;
}

在传入这个Student到Pick中时

type PickStudent1 = Pick<Student, "name">; // 正确
type PickStudent2 = Pick<Student, "score">; // 错误

在上面的Omit实现中,我们用到了 Exclude 这个条件类型,根据上文的说明,Exclude的效果就是寻找在keyof T中有,但在K类型中没有的成员,这样就将剩余的类型过滤了出来,再去应用Pick,就获得了我们的Omit实现。

完整例子:

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

interface Student {
  name: string;
  age: number;
}

type PickStudent1 = Pick<Student, "name">;

参考文档

ly2011 avatar Feb 14 '19 02:02 ly2011