TypeScript细碎知识点:infer 常规用法

一、使用介绍

条件类型基本语法:

 T extends U ? X : Y;

如果占位符类型U是一个可以被分解成几个部分的类型,譬如数组类型元组类型函数类型字符串字面量类型等。这时候可以通过infer来获取U类型中某个部分的类型。

官方解释:现在在有条件类型的 extends 子语句中,允许出现 infer 声明,它会引入一个待推断的类型变量。 这个推断的类型变量可以在有条件类型的 true 分支中被引用。 允许出现多个同类型变量的 infer。
通俗的说:在有条件类型的 extends 子语句中,想要获取哪块的变量类型就在哪里用infer标注这个类型,

!!!重点要记住

  • 只能出现在有条件类型extends的子语句中
  • 引入infer会出现一个待推断的变量
  • 推断的变量只能在truef分支中被引用 。

二、常规用法

1. 数组(或者元组)

🐹 推断数组(或者元组)的类型

定义:

type InferArray<T> = T extends (infer U)[] ? U : never;

(infer U) 和 平时常写的 string[]number[] 等等是不是很像?这里就是通过(infer U)来获取数组对应的类型。

示例

//定义类型工具
type InferArray<T> = T extends (infer U)[] ? U : never;
//示例
type result0 = InferArray<[number, string]>; // string | number
type result1 = InferArray<string[]>;         // string
type result2 = InferArray<number[]>;         // number
🐹 推断数组(或者元组)第一个元素的类型

定义:

type InferFirst<T extends unknown[]> = T extends [infer P, ...infer _] ? P : never

[infer P, ... infer _]infer P获取的是第一个元素的类型,而...infer _获取的是数组其他剩余元素的数组类型;

!!!特别说明下,我们例子汇总不需要使用其他元素的类型,所以用_

示例:

//定义
type InferFirst<T extends unknown[]> = T extends [infer P, ...infer _] ? P : never
//示例
type result = InferFirst<[3, 2, 1]>; // 3
🐹 推断数组(或者元组)最后一个元素的类型

定义:

type InferLast<T extends unknown[]> = T extends [...infer _, infer Last] ? Last : never;

这个 和 推断数组第一个元素的类型 类似,...infer _获取的是最后一个元素之前的所有元素类型,infer Last获取的是最后一个元素的类型。

示例:

//定义
type InferLast<T extends unknown[]> = T extends [...infer _, infer Last] ? Last : never;
//示例
type result = InferLast<[3, 2, 1]> // 1

2. 函数

🐹 推断函数类型的参数

定义:

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

...args 代表的是函数参数组成的元组, infer R代表的就是推断出来的这个函数参数组成的元组的类型。

TS 已内置,名字叫Parameters<T>

示例:

//定义
type InferParameters<T extends Function> = T extends (...args: infer R) => any ? R : never;
//示例
type result = InferParameters<((arg1: string, arg2: number) => void)>; // [string, number]
🐹 推断函数类型的返回值

定义

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

和前面的推断函数类型的参数类似,=> 后面的infer R代表的就是推断出来的函数的返回值类型。

TS 已内置,名字叫ReturnType<T>

示例

//定义
type InferReturnType<T extends Function> = T extends (...args: any) => infer R ? R : never;
//示例
type result = InferReturnType<() => string>; // string
🐹 推断函数类型的构造函数参数类型

定义:

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

我们想获取构造函数的参数类型,是不是只要把infer P标注在构造函数参数的位置就可。这个可以参考推断函数参数去理解

TS 已内置,名字叫ConstructorParameters<T>

示例:

//定义
type InferConstructor<T> = T extends new (...args: infer P) => any ? P : never
//示例
class People {
    name: string;
    constructor(name: string) {
        this.name = name
    }
}
//定义类型
type result = InferConstructor<typeof People>  // string
🐹 4. 推断函数类型的实例类型(InstanceType)

定义:

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

我们想获取构造函数People的实例类型,这个可以参考函数推断返回值去理解。

TS 已内置,名字叫InstanceType<T>。 

示例:

//定义类型
type InferInstanceType<T> = T extends new (...args: any) => infer P ? P : never;
//示例
class People {
    name: string;
    constructor(name: string) {
        this.name = name
    }
}

type result = InferInstanceType<typeof People> //People
🐹 5. 获取this参数的类型(ThisParameterType)

定义:

type InferFuncThisType<T> = T extends (this: infer P, ...args: any) => any ? P : T;
TS 已内置,名字叫ThisParameterType<T>

示例:

// 定义
type InferFuncThisType<T> = T extends (this: infer P, ...args: any) => any ? P : T;
//示例
function fn1(this: { name: string; age: number }) {
    this.name = "Type-Infer";
    this.age = 13;
}
type result = InferFuncThisType<typeof fn1>;

3. Promise

🐹 推断Promise成功值的类型

定义:

type InferPromise<T> = T extends Promise<infer U> ? U : never;

示例:

//定义
type InferPromise<T> = T extends Promise<infer U> ? U : never;
//示例
type result = InferPromise<Promise<string>>; // string

4. 模板类型

🐹 推断字符串字面量类型的第一个字符对应的字面量类型

定义:

type InferString<T extends string> = T extends `${infer First}${infer _}` ? First : [];

示例:

//定义
type InferString<T extends string> = T extends `${infer First}${infer _}` ? First : [];
//示例
type result = InferString<"Johnny">; // J
🐹 去除字符串前面的所有空格

定义:

type TrimFront<T extends string> = T extends `${' '}${infer K}` ? TrimFront<K> : T

示例:

//定义
type TrimFront<T extends string> = T extends `${' '}${infer K}` ? TrimFront<K> : T
//示例
type result = TrimFront<'  Hello'> //Hello
🐹 去除字符串后面的所有空格

定义

type TrimTail<T> = T extends `${infer Res}${' '}` ? TrimTail<Res> : T 

示例

//定义
type TrimTail<T> = T extends `${infer Res}${' '}` ? TrimTail<Res> : T
//示例
type result = TrimTail<'Hello World   '>  //"Hello World"
🐹 实现字符串中某些字符替换(replace)方法

定义:

type InferReplace<T extends string, K extends string, U extends string> = T extends `${infer Left}${K}${infer Right}` ? `${Left}${U}${Right}` : T

示例:

//定义
type InferReplace<T extends string, K extends string, U extends string> = T extends `${infer Left}${K}${infer Right}` ? `${Left}${U}${Right}` : T
//示例
type result = InferReplace<'hello world', 'wo', 'ha'> //'hello harld'
🐹 将字符串的第一个字符转成大些,如果不是字符串,则直接返回。

定义:

type CapitalizeString<T> = T extends `${infer P}${infer V}` ? `${Uppercase<P>}${V}` : T

Uppercase 是 lib.es5.d.ts 的内置方法。

示例:

//定义
type CapitalizeString<T> = T extends `${infer P}${infer V}` ? `${Uppercase<P>}${V}` : T
//示例
type result1 = CapitalizeString<'handler'>  // Handler
type result2 = CapitalizeString<'parent'>   // Parent
type result3 = CapitalizeString<123>        // 123
🐹 获取字符串字面量中的第一个字符

定义:

type FirstChar<T> = T extends `${infer P}${infer _}` ? P : never

示例:

//定义
type FirstChar<T> = T extends `${infer P}${infer _}` ? P : never
//示例
type result1 = FirstChar<'ABC'>  //A
type result2 = FirstChar<'abc'>  //a
type result3 = FirstChar<''>     //never
🐹 获取字符串字面量中的最后一个字符

定义:

type LastChar<T,Pre = never> = T extends `${infer P}${infer V}` ? LastChar<V,P> : Pre

关键点:1. 使用infer关键字配合模版字符串类型推导。 2. prev 临时变量,存储上次首字母。3. extends 递归寻找。

示例:

//定义
type LastChar<T,Pre = never> = T extends `${infer P}${infer V}` ? LastChar<V,P> : Pre
//示例
type result1 = LastChar<'ABC'>  //C
type result2 = LastChar<'abc'>  //c
type result3 = LastChar<''>     //never
🐹 将字符串转成元祖

定义:

type StringToTuple<T extends string> = T extends `${infer L}${infer R}` ? [L, ...StringToTuple<R>] : [];

关键点:1. 使用infer关键字配合模版字符串类型推导。 2. 三点运算符(...)展开数组. 3. extends 递归.

示例:

//定义
type StringToTuple<T extends string> = T extends `${infer L}${infer R}` ? [L, ...StringToTuple<R>] : [];
//示例
type result1 = StringToTuple<'ABC'>  // ['A','B','C']
type result2 = StringToTuple<'abc'>  // ['a','b','c]
type result3 = StringToTuple<''>     // []
🐹 将元组转换成字符串

定义

type TupleToString<T extends any[], Pre extends string = ''> = T extends [infer P, ...infer C] ? (P extends string ? TupleToString<C, `${Pre}${P}`> : never) : Pre

关键点:1. 使用infer配合元组类型推导。 2. extends 递归思想。 3. 使用泛型,增加一个变量使用。

示例

//定义
type TupleToString<T extends any[], Pre extends string = ''> = T extends [infer P, ...infer C] ? P extends string ? TupleToString<C, `${Pre}${P}`> : never : Pre
//示例
type result1 = TupleToString<['A', 'B', 'C']>  // ['A','B','C']
type result2 = TupleToString<['a', 'b', 'c']>  // ['a','b','c]
type result3 = TupleToString<[]>     // []
🐹 将一个泛型复制多分,变成字符串返回

定义

type RepeatString<
    T extends string, // 字符串
    C extends number, // 遍历个数
    S extends string = "", // 临时结果
    A extends any[] = [] // 结束条件
> = A["length"] extends C ? S : RepeatString<T, C, `${T}${S}`, [1, ...A]>;

关键点:1. 使用infer关键字。2. 增加多个变量. 3. 用泛型A约束结束条件,S,存储临时结果。

示例

//定义
type RepeatString<
    T extends string, // 字符串
    C extends number, // 遍历个数
    S extends string = "", // 临时结果
    A extends any[] = [] // 结束条件
> = A["length"] extends C ? S : RepeatString<T, C, `${T}${S}`, [1, ...A]>;

//示例
type result1 = RepeatString<"a", 3>  // "aaa"
type result2 = RepeatString<"a", 0>  // ""
🐹 将字符串字面量类型按照指定字符,分割为元组。无法分割则返回原字符串字面量

定义:

type SplitString<
    T extends string, // 初始字符串
    C extends string, // 分隔符
    B extends string = "", //临时结果
    A extends any[] = [] // 最终结果  SplitString<T,C,S,B,A>
> = T extends `${infer L}${infer R}`
    ? (L extends C ? SplitString<R, C, ``, [...A, B]> : SplitString<R, C, `${B}${L}`, A>)
    : [...A, B];

关键点:1. 使用infer关键字。2. 增加多个变量。3. 用泛型A存储最终结果,B存储临时结果。

示例:

//定义
type SplitString<
    T extends string, // 初始字符串
    C extends string, // 分隔符
    B extends string = "", //临时结果
    A extends any[] = [] // 最终结果  SplitString<T,C,S,B,A>
> = T extends `${infer L}${infer R}`
    ? (L extends C ? SplitString<R, C, ``, [...A, B]> : SplitString<R, C, `${B}${L}`, A>)
    : [...A, B];


//示例
type result1 = SplitString<"handle-open-flag", "-">; // ["handle", "open", "flag"]
type result2 = SplitString<"open-flag", "-">; // ["open", "flag"]
type result3 = SplitString<"handle.open.flag", ".">; // ["handle", "open", "flag"]
type result4 = SplitString<"open.flag", ".">; // ["open", "flag"]
type result5 = SplitString<"open.flag", ".">; // ["open.flag"]
🐹 计算字符串字面量类型的长度

定义:

type LengthOfString<T, RE extends any[] = []> = T extends `${infer L}${infer R}`
    ? LengthOfString<R, [L, ...RE]>
    : RE["length"];

关键点:1. 使用infer关键字。2. 用泛型RE存储最终结果,使用length获取长度返回。

示例:

//定义
type LengthOfString<T, RE extends any[] = []> = T extends `${infer L}${infer R}`
    ? LengthOfString<R, [L, ...RE]>
    : RE["length"];

//示例
type result1 = LengthOfString<"BFE.dev">; // 7
type result2 = LengthOfString<"">; // 0

 

 
 
 

posted on 2024-11-21 20:12  梁飞宇  阅读(270)  评论(0)    收藏  举报