资讯专栏INFORMATION COLUMN

【速查手册】TypeScript 高级类型 cheat sheet

LoftySoul / 2086人阅读

摘要:官方文档高级类型优先阅读,建议阅读英文文档。关键字这个关键字是在版本引入的在条件类型语句中,该关键字用于替代手动获取类型。源码解释使用条件判断完成示例官方作用该类型可以获得函数的参数类型组成的元组类型。

学习 TypeScript 到一定阶段,必须要学会高阶类型的使用,否则一些复杂的场景若是用 any 类型来处理的话,也就失去了 TS 类型检查的意义。

本文罗列了 TypeScript 常用的高阶类型,包含 官方 、以及 常用的非官方 的高级类型声明,该手册直接硬啃的话有些枯燥,适合平时快速查阅,使用 Ctrl+F 来查找关键词来定位即可。

官方文档 - 高级类型:优先阅读,建议阅读英文文档。附 中文文档,有人做了专门的读书笔记 Typescript学习记录:高级类型

TypeScript: Built-in generic types:推荐,用案例详细解释高阶类型的使用;

TS 一些工具泛型的使用及其实现:TS 内置工具泛型高阶使用

TypeScript 2.1 新特性一览:查找/映射类型及 any 类型的推断 都是在 2.1 版本引入的

TypeScript 2.8:Exclude 等条件类型是在 2.8 版本引入的,附中文 TypeScript 2.8 引入条件类型

lib.es2015.d.ts:大部分的声明在这个文件中可以找到

TypeScript 强大的类型别名:行文结构比较合理,也比较完善,可以当手册来查

1、基础 1.1、交叉类型

交叉类型是将 多个类型合并为一个类型。 这让我们可以把现有的多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性。

Person & Serializable & Loggable

同时是 Person 和 Serializable 和 Loggable。

就是说这个类型的对象同时拥有了这三种类型的成员

示例extend 融合方法

function extend(first: T, second: U): T & U {
    let result = {};
    for (let id in first) {
        (result)[id] = (first)[id];
    }
    for (let id in second) {
        if (!result.hasOwnProperty(id)) {
            (result)[id] = (second)[id];
        }
    }
    return result;
}

特殊情况:
T | never = T
T & never = never (which #16446 provides)

1.2、extends 关键字
T extends U ? X : Y

表示,如果 T 可以赋值给 U (类型兼容),则返回 X,否则返回 Y;

1.3、使用 keyofin

keyof 可以用来取得一个对象接口的所有 key 值:

interface Foo {
  name: string;
  age: number
}
type T = keyof Foo // -> "name" | "age"

in 则可以遍历枚举类型, 例如:

type Keys = "a" | "b"
type Obj =  {
  [p in Keys]: any
} // -> { a: any, b: any }

keyof 产生联合类型, in 则可以遍历枚举类型, 所以他们经常一起使用。

1.4、infer 关键字

infer 这个关键字是在 TS 2.8 版本引入的, 在条件类型语句中,该关键字用于替代手动获取类型

TypeScript 为此提供了一个示例,他们创建了一个叫作 Flatten 的类型,用于将数组转成他们需要的元素类型:

type Flatten = T extends any[] ? T[number] : T;

如果使用关键字 infer 就可以将上面的代码简化成:

type Flatten = T extends Array ? U : T;
2、映射类型 2.1、Partial(官方)

作用:将传入的属性变为可选项

源码

type Partial = { [P in keyof T]?: T[P] };

解释

keyof T 拿到 T 所有属性名

然后 in 进行遍历, 将值赋给 P, 最后 T[P] 取得相应属性的值.

结合中间的 ? 我们就明白了 Partial 的含义了.

扩展:内置的 Partial 有个局限性,就是只支持处理第一层的属性,如果是嵌套多层的就没有效果了,不过可以如下自定义:

type PowerPartial = {
    // 如果是 object,则递归类型
    [U in keyof T]?: T[U] extends object
      ? PowerPartial
      : T[U]
};
2.2、Required(官方)

作用:将传入的属性变为必选项

源码

type Required = { [P in keyof T]-?: T[P] };

解释

我们发现一个有意思的用法 -?, 这里很好理解就是将可选项代表的 ? 去掉, 从而让这个类型变成必选项

与之对应的还有个 +? , 这个含义自然与 -? 之前相反, 它是用来把属性变成可选项的

2.3、Readonly(官方)

作用:将传入的属性变为只读选项

源码

type Readonly = { readonly [P in keyof T]: T[P] };

扩展:在 巧用 Typescript 中,作者创建了 DeepReadonly 的声明,使用 递归 的思想让任何子属性都不可更改

type DeepReadonly = {
  readonly [P in keyof T]: DeepReadonly;
}

const a = { foo: { bar: 22 } }
const b = a as DeepReadonly
b.foo.bar = 33 // Hey, stop!
2.4、Mutable(第三方)

作用:将 T 的所有属性的 readonly 移除

源码

type Mutable = {
  -readonly [P in keyof T]: T[P]
}

解释

这一对加减符号操作符 +-, 进行的不是变量的之间的进行加减而是对 readonly 属性进行加减

2.5、Record(官方)

作用:将 K 中所有的属性的值转化为 T 类型

源码

type Record = { [P in K]: T };

示例

// 对所有 T 类型的属性 K, 将它转换为 U
function mapObject(obj: Record, f: (x: T) => U): Record;

const names = { foo: "hello", bar: "world", baz: "bye" };
const lengths = mapObject(names, s => s.length);  // { foo: number, bar: number, baz: number }
2.6、Pick(官方)

作用:从 T 中取出 一系列 K 的属性

源码

type Pick = { [P in K]: T[P] };

示例

// 从 T 挑选一些属性 K
declare function pick(obj: T, ...keys: K[]): Pick;

const nameAndAgeOnly = pick(person, "name", "age");  // { name: string, age: number }
3、条件类型 3.1、Exclude(官方)
某些地方也称为 Diff

作用:从 T 中剔除可以赋值给 U 的类型,换言之就是从T 中排除 U

源码

type Exclude = T extends U ? never : T;

解释

在 ts 2.8 中引入了一个条件类型, T extends U ? X : Y 表示如果 TU 的子类型的话,那么就会返回 X,否则返回 Y

对于联合类型来说会自动分发条件,例如 T extends U ? X : Y, T 可能是 A | B 的联合类型, 那实际情况就变成(A extends U ? X : Y) | (B extends U ? X : Y)

示例

type T = Exclude<1 | 2, 1 | 3> // -> 2

参考文档

Add support for literal type subtraction

TypeScript在React高阶组件中的使用技巧

3.2、Extract(官方)

作用:从 T 中提取出包含在 U 的类型,换言之就是从T 中提取出 U 子集

源码

type Extract = T extends U ? T : never;

示例

type T = Extract<1 | 2, 1 | 3> // -> 1
3.3、Omit (第三方)

作用:从 T 中忽略在 K 中的属性名 ,实现忽略对象某些属性功能,多在高阶组件中使用

源码

type Omit = Pick>

示例

type Foo = Omit<{name: string, age: number}, "name"> // -> { age: number }
3.4、Overwrite(第三方)

作用T 中的定义被在 K 中的内容所覆盖,多在高阶组件中使用,内部借助 Diff 操作实现

源码

type Overwrite = { [P in Exclude]: T[P] } & U;

示例

type Item1 = { a: string, b: number, c: boolean };
type Item2 = { a: number };
type T3 = Overwrite // { a: number, b: number, c: boolean };
3.5、ReturnType (官方)

作用:从 T 中忽略在 K 中的属性名 ,实现忽略对象某些属性功能,多在高阶组件中使用

源码

type ReturnType = T extends (
  ...args: any[]
) => infer R
  ? R
  : any;

解释

我们可以用 infer 声明一个类型变量,是用它获取函数的返回类型,简单说就是用它取到函数返回值的类型方便之后使用.

示例

function foo(x: number): Array {
  return [x];
}
type fn = ReturnType;
4、函数相关 4.1、ThisType(官方)

作用:用于指定上下文对象类型的

源码

// node_modules/typescript/lib/lib.es5.d.ts
interface ThisType { }

解释

可以看到声明中只有一个接口,没有任何的实现

说明这个类型是在 TS 源码层面支持的,而不是通过类型变换。

示例

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

const obj: ThisType = {
  dosth() {
    this.name // string
  }
}

这样的话,就可以指定 obj 里的所有方法里的上下文对象改成 Person 这个类型了

4.2、InstanceType(官方)

作用:用于获取构造函数类型的实例类型

源码

// node_modules/typescript/lib/lib.es5.d.ts

type InstanceType any> = T extends new (...args: any[]) => infer R ? R : any;

解释

使用 inferextends 条件判断完成

示例

class C {
    x = 0;
    y = 0;
}

type T20 = InstanceType;  // C
type T21 = InstanceType;  // any
type T22 = InstanceType;  // any
type T23 = InstanceType;  // Error
type T24 = InstanceType;  // Error

这样的话,就可以指定 obj 里的所有方法里的上下文对象改成 Person 这个类型了

4.3、NonNullable(官方)

作用:这个类型可以用来过滤类型中的 null 及 undefined 类型。

源码

// node_modules/typescript/lib/lib.es5.d.ts

type NonNullable = T extends null | undefined ? never : T;

解释

使用 extends 条件判断完成

示例

type T22 = string | number | null;
type T23 = NonNullable; // -> string | number;
4.4、Parameters(官方)

作用:该类型可以获得函数的参数类型组成的元组类型。

源码

// node_modules/typescript/lib/lib.es5.d.ts

type Parameters any> = T extends (...args: infer P) => any ? P : never;

解释

使用 inferextends 条件判断完成

示例

function foo(x: number): Array {
  return [x];
}

type P = Parameters; // -> [number]

此时 P 的真实类型就是 foo 的参数组成的元组类型 [number]

4.5、ConstructorParameters(官方)

作用:获得类的参数类型组成的元组类型。

源码

// node_modules/typescript/lib/lib.es5.d.ts

type ConstructorParameters any> = T extends new (...args: infer P) => any ? P : never;

解释

使用 inferextends 条件判断完成

示例

class Person {
  private firstName: string;
  private lastName: string;
  
  constructor(firstName: string, lastName: string) {
      this.firstName = firstName;
      this.lastName = lastName;
  }
}

type P = ConstructorParameters; // -> [string, string]

此时 P 就是 Personconstructor 的参数 firstNamelastName 的类型所组成的元组类型 [string, string]

下面的是我的公众号二维码图片,欢迎关注。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/109289.html

相关文章

  • 优质文章汇总(长期更新)

    摘要:阿里蒋航将使前后端从分离再度走向融合阅读原文掀起新的前端技术变革阅读原文速查手册高级类型阅读原文工程化从头搭建一个项目阅读原文文件聊聊中的字段周边深入理解浏览器原理阅读原文 Serverless 1. 阿里蒋航:Serverless 将使前后端从分离再度走向融合 阅读原文 2. Serverless 掀起新的前端技术变革 阅读原文 TypeScript 1. 【速查手册】TypeScr...

    187J3X1 评论0 收藏0
  • 前端开发-从入门到Offer - 收藏集 - 掘金

    摘要:一些知识点有哪些方法方法前端从入门菜鸟到实践老司机所需要的资料与指南合集前端掘金前端从入门菜鸟到实践老司机所需要的资料与指南合集归属于笔者的前端入门与最佳实践。 工欲善其事必先利其器-前端实习简历篇 - 掘金 有幸认识很多在大厂工作的学长,在春招正式开始前为我提供很多内部推荐的机会,非常感谢他们对我的帮助。现在就要去北京了,对第一份正式的实习工作也充满期待,也希望把自己遇到的一些问题和...

    sf_wangchong 评论0 收藏0
  • 初学者必备 | Python Cheat Sheet 中文版

    摘要:笔者整理了中内置方法的速查表,包含内置方法列表处理方法字典处理方法元组处理方法集合处理方法序列类型的切片方法共计多个方法,点击图片查看原图下载。 笔者整理了Python3中内置方法的速查表,包含: 内置方法 列表处理方法 字典处理方法 元组处理方法 集合处理方法 序列类型的切片方法 共计100多个方法,点击图片——查看原图——下载。 showImg(https://sfault-i...

    Terry_Tai 评论0 收藏0
  • Laravel 5.1 LTS 速查表重磅发布

    showImg(http://ww2.sinaimg.cn/large/005SFY0kjw1f2mt468a0cj31bs10mtk8.jpg); GitHub 项目在此: https://github.com/Aufree/laravel5-cheat... 本项目由 @Aufree 和 @Summer 整理维护。 说明 最近在开始使用 Laravel 进行开发, 在学习过程中无意间发现了 L...

    20171112 评论0 收藏0
  • AI开发书籍分享

    摘要:编程书籍的整理和收集最近一直在学习深度学习和机器学习的东西,发现深入地去学习就需要不断的去提高自己算法和高数的能力然后也找了很多的书和文章,随着不断的学习,也整理了下自己的学习笔记准备分享出来给大家后续的文章和总结会继续分享,先分享一部分的 编程书籍的整理和收集 最近一直在学习deep learning深度学习和机器学习的东西,发现深入地去学习就需要不断的去提高自己算法和高数的能力然后...

    huayeluoliuhen 评论0 收藏0

发表评论

0条评论

LoftySoul

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<