乐趣区

关于typescript:TypeScript类型编程中extends和infer

引文

在刚接触 TypeScript 的时候,应用最多的就是 type 和 interface 这两个关键字,用来申明类型,其实这样也根本满足日常需要。然而如果须要设计一些高级类型的话,那么仅仅用原来所把握的 TypeScript 常识是无奈满足需要的。

设计高级类型的话波及到类型编程的知识点,而类型编程中有两个关键字十分重要,别离是 extends 和 infer。

extends 用来束缚入参的类型以及进行条件判断,infer 用来申明部分的类型变量。

extends

条件判断

咱们举个简略的例子来阐明

type isOne<T extends number> = T extends 1 ? true : false

咱们独自看 T extends 1 ? true : false 这部分,这里和 JavaScript 中的三元表达式并无二致,然而有些同学不分明其中 extends 示意的是什么含意。

T extends 1 ? true : false 示意的含意其实就是传入的 T 类型是否可能赋值给字面量 1 这个类型,如果能够的话,就返回 true,否则返回 false

束缚参数类型

持续应用下面的例子,咱们独自看T extends number,这里 extends 的意思就是限度传入的 T 类型必须是 number 类型,否则报错。

为什么须要有这个限度?

因为咱们是要判断类型 T 是否可能赋值给字面量类型 1,然而如果传入的参数都不是 number 类型,那么就没必要做后续的条件判断了。

束缚 infer 推导的局部变量类型

type GetFirst<T extends string[]> = T extends [infer FirstChar, ...infer Rest]
  ? `${FirstChar}`
  : never;

type Res = GetFirst<['1', '2', '3']>;

来看看报错信息,咱们传入的参数类型限度为 sting 类型的数组,然而 infer 推导进去的类型实际上是 unknown 类型,所以导致类型不匹配。

解决办法有三种:

  • 对 FirstChar 应用 extends 先做过滤

    type GetFirst<T extends string[]> = T extends [infer FirstChar, ...infer Rest]
    ? FirstChar extends string
      ? `${FirstChar}`
      : never
    : never;
  • FirstChar 和 string 进行穿插运算

    type GetFirst<T extends string[]> = T extends [infer FirstChar, ...infer Rest]
    ? `${FirstChar & string}`
    : never;
  • 应用 infer extends 做类型转换

    type GetFirst<T extends string[]> = T extends [
    infer FirstChar extends string,
    ...infer Rest
    ]
    ? `${FirstChar}`
    : never;

    infer extends是在 ts 4.7 版本反对,低于这个版本无奈应用。

    类型转换

    type StrToNum<T extends string> = T extends `${infer Num extends number}` ? Num : T
    
    type Res = StrToNum<"1">
    
    // ts 4.7 时,返回的后果是 type Res = number
    // ts 4.8 及以上,返回的后果是 type Res = 1

    infer

    还是拿例子来进行解说,上面的例子是要提取 Promise 包裹的类型。

    type PromiseValue<T extends Promise<unknown>> = T extends Promise<infer Value> ? Value : never
    
    type Res = PromiseValue<Promise<string>> // string

    画个简略的图来形容下如何提取变量类型。

留神:infer 申明的局部变量,只能在条件语句为 true 的分支外面应用。

间接报错示意找不到通过 infer 申明的局部变量。

组合应用

ReturnType

内置工具类型 RetureType 用于获取函数的返回值类型。

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

type Res = MyReturnType<() => string> // type Res = string

Parameters

内置工具类型 Parameters 用于获取函数的参数类型。

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

type Res = MyParameters<(a: string, b: number) => void>  // type Res = [a: string, b: number]
退出移动版