当前位置:网站首页>TS advanced infer

TS advanced infer

2022-06-23 04:40:00 JonnyLan

In the previous article, we introduced condition types , In this article, let's introduce a very practical infer How to use .

Introduction

The basic syntax of conditional types introduced in our last article is :

 T extends U ? X : Y;

If the placeholder type U Is a type that can be broken down into several parts , For example, array type , A tuple type , Function type , String literal type, etc . At this time, you can go through infer To get U The type of a part of a type .

infer The grammatical restrictions are as follows :

  1. infer Only in conditional type of extends Used in clauses
  2. infer The type obtained can only be in true Use in statement , namely X Use in

Infer array ( Or tuple ) The type of

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

(infer U) Peace often writes string[],number[] Wait, is it like ? And here is through (infer U) To get the type corresponding to the array .

Case study
type I0 = InferArray<[number, string]>; // string | number
type I1 = InferArray<string[]>; // string
type I2 = InferArray<number[]>; // number

Infer array ( Or tuple ) The type of the first element

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

[infer P, ... infer _] in infer P Acquired Is the type of the first element , and ...infer _ Get the array type of other remaining elements of the array ;
In particular , Our example summary does not need to use the types of other elements , So use _.

Case study
type I3 = InferFirst<[3, 2, 1]>; // 3

Infer array ( Or tuple ) The type of the last element

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

This and Infer the type of the first element of the array similar ,...infer _ Get all the element types before the last element ,infer Last Get the type of the last element .

Case study
type I4 = InferLast<[3, 2, 1]>; // 1

Infer parameters of function types

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

...args Represents a tuple of function parameters , infer R Represents the type of tuple formed by the inferred function parameters .

Case study
type I5 = InferParameters<((arg1: string, arg2: number) => void)>; // [string, number]

Infer the return value of a function type

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

And the one in front Infer parameters of function types similar ,=> hinder infer R Represents the return value type of the inferred function .

Case study
type I6 = InferReturnType<() => string>; // string

infer Promise Type of success value

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

Case study
type I7 = InferPromise<Promise<string>>; // string

Infer the literal type corresponding to the first character of the string literal type

Usage method
type InferString<T extends string> = T extends `${infer First}${infer _}` ? First : [];
Case study
type I8 = InferString<"Johnny">; // J

Comprehensive case

Let me give you some comprehensive examples , I will not introduce the functions implemented by these examples , Let's feel it infer Use skills , See if you can see the functions at a glance :

type Shift<T> = T extends [infer L, ...infer R]? [...R] : [];
type Pop<T extends any[]> = T extends [...infer L, infer R] ? [...L] : [];
type Reverse<T extends unknown[], U extends unknown[] = []> = [] extends T
  ? U
  : T extends [infer L, ...infer R]
  ? Reverse<R, [L, ...U]>
  : U;
type FlipArguments<T extends Function> = T extends (...arg: infer R) => infer S ? (...arg : Reverse<[...R]>) => S : T;
type StartsWith<T extends string, U extends string> = T extends `${U}${infer R}` ? true : false;
type TrimLeft<S extends string> = S extends `${infer L}${infer R}`
  ? L extends ' ' | '\n' | '\t'
    ? TrimLeft<R>
    : S
  : '';
type Trim<S extends string> = S extends `${' ' | '\t' | '\n'}${infer R}`
  ? Trim<R>
  : S extends `${infer L}${' ' | '\t' | '\n'}`
  ? Trim<L>
  : S;
type StringToUnion<T extends string, U = never> = T extends ''
  ? U
  : T extends `${infer L}${infer R}`
  ? StringToUnion<R, U | L>
  : U;

These examples involve two knowledge points that are not introduced : Template literal type and Recursive type , If you don't understand these two knowledge points, you can refer to other articles . I will also introduce these two knowledge points later .

原网站

版权声明
本文为[JonnyLan]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/174/202206222337130218.html