TypeScript 里 infer 常见用法

1 什么是「infer」

1.1 概念

infer 只能在 条件类型(conditional types) 中使用,用来 在类型推断时声明一个待推断的类型变量

语法为:

typescript 复制代码
T extends SomeType<infer U> ? U : never

可以这么理解:

  • 如果 T 能匹配 SomeType<某个类型> 的结构
  • 那么把内部类型推断为 U
  • 然后返回 U

1.2 特点

1.2.1 只能在 extends ? : 中使用

不能单独写,比如下边这么写就是错的:

typescript 复制代码
type A = infer T; 

1.2.2 右侧的类型结构必须能匹配

typescript 复制代码
type A<T> = T extends [infer U] ? U : never;

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

2 基本用法

2.1 提取函数返回值类型

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

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

infer R 就是 推断函数的返回值类型

2.2 提取参数类型

typescript 复制代码
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 提取数组元素类型

typescript 复制代码
type ElementOf<T> = T extends (infer U)[] ? U : never;

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

2.4 提取 tuple 的某个元素

typescript 复制代码
type First<T> = T extends [infer F, ...any[]] ? F : never;

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

在这个例子中,我们提取的是 tuple 的第一个元素。

2.5 提取对象中某个 key 的类型

typescript 复制代码
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 对象路径提取

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

假设说我们有这么一个类型:

typescript 复制代码
type User = {
  id: number;
  name: {
    first: string;
    last: string;
  };
  address: {
    city: string;
    location: {
      lat: number;
      lng: number;
    };
  };
};

执行 Path

typescript 复制代码
type UserPath = Path<User>;

之后得到的结果展开就是:

typescript 复制代码
type UserPath =
  | "id"
  | "name.first"
  | "name.last"
  | "address.city"
  | "address.location.lat"
  | "address.location.lng";

3 总结

本文总结了 TypeScript 中 infer 的常见用法,可以说 infer 是 TypeScript 里各种类型体操的基础,基于它可以实现各种「高级」类型。

相关推荐
学网安的肆伍31 分钟前
【046-WEB攻防篇】注入工具&SQLMAP&Tamper编写&指纹修改&高权限操作&目录架构
前端·架构
Highcharts.js2 小时前
如何下载使用Highcharts Grid 开发web可编辑表格
前端·人工智能·grid 表格·web 表格·在线编辑表格·highcharts表格安装·表格开发工具
用户62960593247052 小时前
从“浏览器根本区分不了”到真正实现:刷新不退出,关闭标签页自动退出,前端判断浏览器关闭和刷新
前端
qetfw2 小时前
MWU:Vue 3 + FastAPI 的 MaaFramework 跨平台 WebUI 源码
前端·vue.js·python·fastapi·开源项目·效率工具
mfxcyh2 小时前
Vue3+Ant Design Vue 实现手动异步文件上传(含大小校验、弹窗上传)
前端·javascript·vue.js
wordbaby2 小时前
Web端热敏标签打印完整解决方案(QZ Tray + 译维A42)
前端
swipe2 小时前
03|Axios 请求进了后端之后:Controller、Request、Response 是怎么接住它的?
前端·后端·全栈
meilindehuzi_a2 小时前
Vue3进阶基础:指令修饰符、v-model表单绑定、动态样式、计算属性与侦听器实战
前端·javascript·vue.js
csdn2015_3 小时前
vue 前端运行命令
前端·javascript·vue.js
swipe3 小时前
02|从 `pnpm dev` 到 Spring Boot 启动:后端服务到底怎么跑起来?
前端·后端·全栈