博客 / 詳情

返回

TypeScript 裏 infer 常見用法

1 什麼是「infer」

1.1 概念

infer 只能在 條件類型(conditional types) 中使用,用來 在類型推斷時聲明一個待推斷的類型變量

語法為:

T extends SomeType<infer U> ? U : never

可以這麼理解:

  • 如果 T 能匹配 SomeType<某個類型> 的結構
  • 那麼把內部類型推斷為 U
  • 然後返回 U

1.2 特點

1.2.1 只能在 extends ? : 中使用

不能單獨寫,比如下邊這麼寫就是錯的:

type A = infer T; 

1.2.2 右側的類型結構必須能匹配

type A<T> = T extends [infer U] ? U : never;

type B = A<[string]>; // string
type C = A<string>;   // never

2 基本用法

2.1 提取函數返回值類型

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

type A = ReturnType<() => number>;
// A = number

infer R 就是 推斷函數的返回值類型

2.2 提取參數類型

type FirstArg<T> = T extends (arg: infer P, ...args: any[]) => any ? P : never;

type A = FirstArg<(x: string, y: number) => void>;
// A = string

2.3 提取數組元素類型

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

type A = ElementOf<string[]>; 
// A = string

2.4 提取 tuple 的某個元素

type First<T> = T extends [infer F, ...any[]] ? F : never;

type A = First<[string, number, boolean]>;
// A = string

在這個例子中,我們提取的是 tuple 的第一個元素。

2.5 提取對象中某個 key 的類型

type PropType<T, K extends keyof T> = 
  T extends { [Key in K]: infer R } 
    ? R 
    : never;

type A = PropType<{name: string; age: number}, 'age'>;
// A = number

2.6 對象路徑提取

type Path<T> = {
    [K in keyof T]: 
        T[K] extends object 
          ? `${string & K}.${Path<T[K]>}`
          : `${string & K}`;
}[keyof T];

假設説我們有這麼一個類型:

type User = {
  id: number;
  name: {
    first: string;
    last: string;
  };
  address: {
    city: string;
    location: {
      lat: number;
      lng: number;
    };
  };
};

執行 Path

type UserPath = Path<User>;

之後得到的結果展開就是:

type UserPath =
  | "id"
  | "name.first"
  | "name.last"
  | "address.city"
  | "address.location.lat"
  | "address.location.lng";

3 總結

本文總結了 TypeScript 中 infer 的常見用法,可以説 infer 是 TypeScript 裏各種類型體操的基礎,基於它可以實現各種「高級」類型。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.