likes
comments
collection
share

TS中高级类型工具及其源码解析(含示例)

作者站长头像
站长
· 阅读数 73

一、前言

最近入职了新公司也有两个月左右了,公司主要技术栈是 ReactTS,然而我平时用的TS并不多,刚好借此机会最近也是好好的学习了一番TS的高级工具类型及其源码

本文主要介绍的是TS的高级类型工具,含有TS高级类型工具的源码解释,及其示例,需要对TS有一定了解,或者已经实际用过一段时间

二、前置知识

1、关键字 extends

准确的来说这是一个条件类型,它借用了 javascript 的条件运算符,语法如下

T extends U ? X :Y

解释:

  • 在该语法示例中, extends 是关键字; T、 U、 X 和 Y 均表示一种类型
  • 若类型 T 能赋值给类型 U,则条件类型的结果就是类型 X,反之结果为类型 Y
  • 当然这个关键字如果用到 interface 上就是继承的作用了,这儿就不做过多的解释

2、关键字 in

这是一个遍历语法的关键字, 语法如下

type K = "a" | "b"

type B = { [P in K]: number } // { a: number; b: number}

解释:

  • 在结果对象类型中创建一个新的属性成员, 属性名为P, 属性值为 number
  • P 是类型变量,代表每次遍历出来的成员类型,并且 P 可以作为对象属性值的类型 类似这样:[P in K]: P
  • K 表示要遍历的类型, 由于遍历的结果类型要作为对象属性名, 因此类型 K 必须能够赋值给联合类型 string | number | symbol

3、关键字 readonly

这个比较简单,就代表了这个类型是否为只读类型

interface A {
    readonly a: string;
    b: number;
}

const test: A = {
    a: "",
    b: 0
}

test.b = 1;
// test.a = "1" // a 为 readonly 不可更改

4、关键字 keyof

用来获取一个类型的键值,并返回一个联合类型

interface A {
    a: number;
    b: string;
}

type B = keyof A; // "a" | "b"

5、关键字 typeof

这是一个类型查询的关键字,可以获取操作数的类型

const A = {
    a: 1,
    b: "2"
}

type B = typeof A; // { a: number; b: string }

5、关键字 infer

这个关键字主要用来定义一个可推断的类型, 用的比较多的地方就是用来获取函数的参数类型

type CT<T> = T extends Array<infer U> ? U : never;
type T = CT<Array<number>> // number


type CT1<T> = T extends (arg: infer U) => void ? U : T;
type T1 = CT1<(a: boolean) => void> // boolean

6、修饰符的加减

TS中引入了两个修饰符来精确控制添加或者移除映射属性的 "?" 修饰符readonly 修饰符

type T0<T> = { -readonly [P in keyof T]-?: T[P] };
type T1<T> = { +readonly [P in keyof T]+?: T[P] };

解释:

  • "+" 修饰符,为映射属性添加 "?" 修饰符或者 readonly
  • "-" 修饰符,为映射属性移除 "?" 修饰符或者 readonly
  • "+" 或者 "-" 修饰符必须应用在 "?" 修饰符或者 readonly 之前
  • 对于 "+" 修饰符, 明确的添加与省略它的作用是相同的,所以通常都省略。 例如 "+readonly" 等同于 "readonly"

三、高级类型工具

1. Partial<T>

源码:

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

该工具类型可以构造一个新的类型,并把实际类型参数 T 中的属性全变成可选属性

  interface A {
    x: number;
    y: number;
  }
  type T = Partial<A>; // {x?number; y?:number}}

2. Required<T>

源码:

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

Partial 相反, 把T 中的属性全变成必选属性

  interface A {
    x?: number;
    y: number;
  }

  type T = Required<A>; // {x:number; y:number}}

3. Readonly<T>

源码:

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

该工具类型可以构造一个新的类型, 并将类型参数 T 中的所有属性变成只读属性

  interface A {
    x: number;
    y: number;
  }

  type T = Readonly<A>; // {x:number; y:number}}
  const a: T = { x: 0, y: 0 }
  // a.x = 1  无法分配到 "x" ,因为它是只读属性
  // a.y = 1  无法分配到 "y" ,因为它是只读属性

4. Record<K, T>

源码:

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

该工具类型可以使用给定的 对象属性名类型 和 对象属性类型,创建一个新的对象类型

  type K = 'x' | 'y';
  type T = number;
  type R = Record<K, T>; // {x:number; y:number}} 
  const a: R = { x: 0, y: 0 }

5. Exclude<T, U>

源码:

  type Exclude<T, U> = T extends U ? never : T;

该工具类型可以从类型 T 中剔除所有可以赋值给类型 U 的类型

  type T0 = Exclude<"a" | "b", 'x'>; // "a" | "b"
  type T1 = Exclude<string | (() => void), Function>; // string

6. Extract<T, U>

源码:

  type Extract<T, U> = T extends U ? T : never;

该工具类型和 Exclude<T, U>类型互补, 它能从类型 T 中获取所有可以赋值给类型 U 的类型

  type T0 = Extract<"a" | "b", 'a'>;  // "a"
  type T1 = Extract<string | (() => void), Function>; // () => void
  type T2 = Extract<"a" | "b", 'c'>;  // never

7. Pick<T, K>

源码:

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

该工具能出已有对象类型中选取给定的属性以及其类型,然后构建一个新的对象类型

  interface A {
    x: number;
    y: number;
  }
  type T0 = Pick<A, 'x'>; // {x:number}
  type T1 = Pick<A, 'x' | 'y'>; // {x:number; y:number}

  // type T3 = Pick<A, 'z'> 类型“"z"”不满足约束“keyof A”

8. Omit<T, K>

源码:

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

该工具与 Pick<T, K> 类型互补,能从已有对象类型中剔除给定的属性,然后构建一个新的对象类型

  interface A {
    x: number;
    y: number;
  }

  type T0 = Omit<A, 'x'>; // {y:number}
  type T1 = Omit<A, 'x' | 'y'>; // {}
  type T3 = Omit<A, 'z'>; // {}

9. NonNullable<T>

源码:

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

该工具类型能从类型 T 中剔除 null 和 undefined 类型,并构建一个新的类型

type T0 = NonNullable<string | number | null | undefined>; // string | number

10. Parameters<T>

源码:

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

该工具类型能获取函数类型 T 的参数类型,并使用参数类型构建一个元组类型

  type T0 = Parameters<() => void>; // []
  type T1 = Parameters<(a: string) => void>; // [string]
  type T2 = Parameters<(a: string, b: number) => void>; // [string, number]
  type T3 = Parameters<(x: { a: number, b: string }) => void>; // [{ a: number; b: string }]

11. ConstructorParameters<T>

源码:

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

该工具类型能获取构造函数 T 中的参数类型, 并使用参数类型构造一个元组类型。 若 T 不是函数类型,则`返回 never 类型

type T0 = ConstructorParameters<new (s?: string) => object>; //  [s?: string | undefined]

12. ReturnType<T>

源码:

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

该工具类型能获取函数类型 T 的返回值类型

  type T0 = ReturnType<() => string>; // string
  type T1 = ReturnType<() => { a: string, b: number }>; // { a: string; b: number }

13. InstanceType<T>

源码:

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

该工具类型能获取构造函数的返回值类型

  class A {
    x = 0;
  }

  type T0 = InstanceType<typeof A>; // A
  type T1 = InstanceType<new (s?: string) => object>; // object

14. ThisParameterType<T>

源码:

  type ThisParameterType<T> = T extends (this: infer U, ...args: any[]) => any ? U : unknown;

该工具类型能获取函数类型 T 中的 this 参数类型,若函数类型定义中没有 this 参数,则返回 unknown 类型

  function fn(this: object, x: number) { }
  function fn1(x: number) { }

  type T0 = ThisParameterType<typeof fn> // object
  type T1 = ThisParameterType<typeof fn1> // unknown

15. OmitThisParameter<T>

源码:

 type OmitThisParameter<T> = unknown extends ThisParameterType<T> ? T : T extends (...args: infer A) => infer R ? (...args: A) => R : T;

该工具类型能从类型 T 中剔除 this 参数类型,并构造一个新类型

  function fn(this: object, x: number) { }

  type T0 = OmitThisParameter<typeof fn> // (x: number) => void

四、结语

本文中,对常见的关键字和常用的高级类型工具进行了讲解, 主要平时开发的时候还是要多用、多积累。

最后,文中如有错误,欢迎大家在评论区指正,如果本文对你有帮助, 记得点赞👍关注❤️

如需转载请标明作者和出处


转载自:https://juejin.cn/post/7100737388128763918
评论
请登录