诶,有人会问,这是进阶文章,那有没有基础呢?
很遗憾,暂时没有,需要的话,评论区告诉我😄

内置函数是什么

函数在数学上,就是自变量到因变量的映射。想得到什么样的输出,那给它的输入就是确定的;或者给它什么样输入,他就会有一个固定的输出
而TS内置函数就是一种类型到另一种类型的映射,你也可以理解成类型的转换
OK,我们开始

NonNullable

接收一个联合类型,返回的结果中会去掉Type中的null和undefined类型
下面是使用代码:

  1. type test1 = NonNullable<null | undefined | string | number>;

image.png

由函数转换过后的联合类型,只剩下string | number

下面是手动实现

  1. type MyNonNullable<T> = T extends null | undefined ? never : T;
  2. type test2 = MyNonNullable<null | undefined | string | number>;

image.png

效果符合预期

理解:如果泛型T可以转成null | undefined,或者说是null | undefined的子类,那么就返回never,否则返回T。

关键点是如何识别T是否为null | undefined

Parameters

接收一个函数类型,返回这个函数的参数数组
下面是使用代码:

  1. type testParam = Parameters<(a: number, b: number) => void>;

image.png

得到的类型是一个数组,也可以说是元组。数组里面每一项都和函数的参数的类型一致

下面是手动实现:

  1. type MyParamters<T extends Function> = T extends (...args: infer K) => any ? K : never;
  2. type testParam2 = MyParamters<(a: number, b: number) => void>;

image.png

效果符合预期 这里用到了extends来判断T是属于哪种类型的函数,然后用infer来获取参数的类型,或者说用K来代表参数的类型

ConstructorParameters

接收一个构造器类型,返回构造函数中需要的参数类型
下面是使用方法:

  1. interface person {
  2. new (name: string, age: number): otherType; // 返回其他类型
  3. setAge(newAge: number): number;
  4. }
  5. interface Animal {
  6. new (name: string, isBig: boolean): otherType; // 返回其他类型
  7. setName(newName: string): number;
  8. }
  1. type testConstru = ConstructorParameters<person>;

image.png

  1. type testConstru = ConstructorParameters<Animal>;

image.png
下面是手动实现

  1. type MyConstructorParameters<T extends new (...keys: any) => any> = T extends new (...keys: infer K) => any ? K : never;

解释:

  1. 要求传入的是”定义了构造函数的接口“,或者”typeof class“。不按要求传入接口和class,都会报错。

    为啥要typeof class,我们知道class既可以当作值来使用,或者是类型来使用。而在typeof 语法中,会将class看作值,而class的本质就是构造函数,那么typeof class就是获取class对应的构造函数的类型。

  2. 返回的K就是构造函数的参数

题外Tips:

  1. 和JS不同,TS中不能由函数来定义构造函数,也就是说,new 一个函数会报错。

    为什么会这样,因为在TS中,把函数定义和构造函数的定义完全分开了

image.png

  1. 再说一下class 和 typeof class的区别,这理解构造函数很重要 ```typescript class Person { constructor(public personName: string, public personAge: string) {} getName() {
    1. return this.personName;
    } setName(newName: string) {
    1. this.personName = newName;
    } static laugh(){ console.log(‘laugh’); } }

const p1 = {} as Person;

const p2 = {} as typeof Person;

  1. > 上面的代码中,p1是获取Person的实例类型,p2是获取Person的构造函数类型
  2. 我们来看下面的截图,就能更清楚地理解了:<br />![image.png](https://cdn.nlark.com/yuque/0/2022/png/27760829/1654877192260-20e738d8-d0b6-4373-8748-025e630a1047.png#clientId=u1bd96d54-00ed-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=172&id=u5c287930&margin=%5Bobject%20Object%5D&name=image.png&originHeight=344&originWidth=932&originalType=binary&ratio=1&rotation=0&showTitle=false&size=39465&status=done&style=none&taskId=u1849903c-2948-4e74-b5ce-63c523d3045&title=&width=466)
  3. > p1所能访问的属性,和实例化class Person后对象的属性一致
  4. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/27760829/1654877250150-c4b70a2f-5dae-496b-96f9-f8c986aa1722.png#clientId=u1bd96d54-00ed-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=344&id=ub63f6ecb&margin=%5Bobject%20Object%5D&name=image.png&originHeight=688&originWidth=988&originalType=binary&ratio=1&rotation=0&showTitle=false&size=70650&status=done&style=none&taskId=u102d8e65-8365-4eb6-8894-ca87c4dde23&title=&width=494)
  5. > p2所能访问的属性,有静态属性laugh--构造函数的属性;还有其他的属于Function的属性
  6. <a name="bL2Yo"></a>
  7. ## ReturnType<Type>
  8. 接收一个函数类型的Type,返回函数的返回类型<br />下面是用法:
  9. ```typescript
  10. type testReturn = ReturnType<(a: string) => number>;

image.png
下面是手动实现:

  1. type MyReturnType<T extends Function> = T extends (...keys: any[]) => infer R ? R : never;
  2. type testReturn2 = MyReturnType<(a: string) => [number, string]>;

image.png
解释:我们用推断类型,来用R表示函数的返回类型;用条件类型来返回R。整体逻辑:如果T是这种函数的子类,就返回它的返回类型R

InstanceType

也没什么神奇的,就是获取构造函数的返回类型
下面是用法:

  1. interface person {
  2. new (personName: string, personAge: number): instancePerson;
  3. }
  4. interface instancePerson{
  5. personName: string;
  6. personAge: number;
  7. setName(newName: string): number;
  8. }
  9. type testInstance = InstanceType<person>;

image.png

传入的参数和ConstructorParameters一致,需要传入一个定义了构造函数的接口,和typeof class

下面是手动实现:

  1. type MyInstanceType<T extends new (...keys: any)=>any > = T extends abstract new (...keys: any) => infer R ? R : never;

解释:

  1. 官方源码在每个new前面都加了一个 abstract,我试了下,效果都一样,可加可不加
  2. 整体逻辑,先判断传进来的是否为构造函数类型,然后再获取它的返回类型
  3. 使用场景:获取VUE组件的实例

ThisParamterType

获取函数的this类型
下面是用法:

  1. function toHex(this: Number) {
  2. return this.toString(16);
  3. }
  4. function numberToString(n: ThisParameterType<typeof toHex>) {
  5. return toHex.apply(n);
  6. }
  1. 这个例子有点绕
  2. 先声明一个’数字转16进制‘的函数toHex,这个函数需要调用传入参数的toString属性。在内部的做法是用this.toString,所以在参数部分就要定义this的类型—Number。
  3. 定义this的类型,一般是放在形参的第一个位置。而在调用该函数的时候,并不需要传入this这个实参。
  4. 内部的this由调用该函数的对象决定,或者用apply、bind、call强制绑定。在上面的例子中,就用apply强制绑定了toHex函数的this为n
  5. numberToString的函数参数中,取了toHex的函数的this类型。其中函数不能直接作为类型使用,所以需要加typeof

下面是手动实现:

  1. type myThisParamterType<T> = T extends (this: infer F, ...args: any)=>any ? F : never;
  2. type testmyThisParamterType = myThisParamterType<typeof toHex>

image.png
解释:

  1. 可以在传入泛型位置加一个类型的约束,比如 type myThisParamterType<T exnteds (...args: any)=>any>,约束传进来的函数,不是函数就报错。这个可加可不加,看个人喜好
  2. 整体逻辑和上面的相似,就不赘述了

总结:

  1. 这篇文章描述了一些比较难理解的TS内置函数,
  2. 从‘使用’和’手动实现‘两个角度分别对每个内置函数进行阐述
  3. 除了获得内置函数的理解之外,还知道了class和typeof class的区别,还知道了this在TS的使用
  4. 文中还提到了一些条件类型,推断类型的使用,这个在TS进阶的领域是很重要的,我之后会专门写篇文章来从我的角度对这知识进行阐述
  5. 下篇文章讲最后一个和this有关的内置函数,ThisType,理解了这个函数,相信在以后的TS编写过程中,会有了更强的类型约束的意识
  6. 如果有不明白的地方,评论区告诉我,或者加我微信