Skip to content

TS 面试题:infer 关键字 标准回答(话术 + 极简代码)

面试口语回答(直接背,自然流畅)

面试官您好,infer 是 TypeScript 里专门用在条件类型中的关键字,核心作用就是提取、推断出某个类型内部的子类型,可以理解成类型层面的“变量声明”

它不能单独使用,必须搭配 T extends 判断条件 ? 成功 : 失败 的条件类型语法,在 extends 右侧的待推断位置用 infer 变量名 捕获未知类型,捕获后就能在条件为真的分支里使用这个推断出来的类型。

日常最常用的场景就是:提取函数返回值类型、提取函数参数类型、提取数组元素类型、提取 Promise 内部类型,TS 内置的 ReturnTypeParameters 这些工具类型底层都是用 infer 实现的。


核心语法规则

  1. 只能在条件类型中使用,不能单独写
  2. 格式:T extends 推断模板<infer R> ? R : 其他类型
  3. infer R 就是声明一个类型变量 R,用来接住被提取的类型

高频代码示例(面试必写)

1. 手写 ReturnType:提取函数返回值类型

ts
// 用 infer 提取函数返回值类型 R
type MyReturnType<T> = T extends (...args: any[]) => infer R ? R : never

// 测试
type Fn = () => string
type Res = MyReturnType<Fn> // Res 类型为 string

2. 提取函数参数类型

ts
// 提取函数第一个参数类型
type MyParameters<T> = T extends (arg: infer P) => any ? P : never

type Fn2 = (name: string) => void
type Param = MyParameters<Fn2> // Param 类型为 string

3. 提取数组元素类型

ts
// 提取数组里的元素类型
type ElementType<T> = T extends (infer E)[] ? E : never

type Arr = number[]
type Ele = ElementType<Arr> // Ele 类型为 number

4. 提取 Promise 内部类型

ts
// 提取 Promise 包裹的类型
type PromiseType<T> = T extends Promise<infer P> ? P : never

type P = Promise<boolean>
type Data = PromiseType<P> // Data 类型为 boolean

面试总结(收尾加分)

infer 本质就是类型推导的“捕获工具”,专门用来从复杂类型里抠出我们需要的子类型,是 TS 高级类型的核心关键字,也是判断候选人 TS 水平的一个小考点。


我用最通俗的面试话术 + 大白话比喻 + 极简代码,把 infer泛型 的关系讲透,完全贴合你之前的理解,面试官听了直接懂你掌握了核心:

面试问题:infer 关键字和泛型有什么关系?

一、面试口语标准答案(直接背)

面试官您好,泛型和 infer 本质都是「TypeScript 的类型变量工具」,是分工不同、配合使用的黄金搭档:

  1. 泛型(T/U)提前声明的「外部类型参数」,作用是从外部传入类型,给整个函数 / 类型公用;
  2. infer R临时声明的「内部类型变量」,作用是在条件类型里「提取 / 捕获」藏在内部的子类型
  3. 核心关系:infer 不能单独使用,必须依赖泛型 + 条件类型才能生效,它们一起实现了 TS 高级类型的「类型提取」能力。

二、大白话比喻(秒懂,面试加分)

类型处理比作 「拆快递」

  • 泛型 <T> = 你提前准备好的快递盒子,从外面把「包裹(类型)」装进来,是入口传参
  • infer R = 你打开盒子后,临时抓取盒子里的小物品(子类型),只在拆快递时用,是内部提取

三、核心关系(3 个关键点)

  1. 本质相同:都是给「类型」起临时名字(类型变量),只是声明方式不一样;

  2. 分工相反

    • 泛型:外部 → 内部(主动传类型)
    • infer:内部 → 外部(被动抓类型)
  3. 依赖关系没有泛型,infer 根本用不了;infer 是泛型的「高级辅助工具」。


四、一体代码示例(最直观,同时包含泛型 + infer)

这是 TS 最经典的工具类型 ReturnType一行代码同时用到泛型和 infer,我给你标出来:

ts
// 👇 <T> 是【泛型】:外部传入的类型参数(入口)
type MyReturnType<T> = 
  // 👇 infer R 是【infer 变量】:临时提取函数的返回值类型(内部捕获)
  T extends (...args: any[]) => infer R ? R : never;

// 使用:传入泛型 T = 函数类型
type Fn = () => string;
type Res = MyReturnType<Fn>; // Res = string

代码拆解

  1. 泛型 <T>:接收外部的函数类型 () => string
  2. infer R:在类型内部,把函数的返回值 string 抓出来,命名为 R
  3. 最终返回 R,完成「提取」。

五、一句话总结(面试收尾)

泛型是「传类型」,infer 是「抓类型」;泛型是入口,infer 是内部工具,两者配合实现 TS 高级类型提取。


补充:最容易混淆的点(帮你避坑)

  • 泛型 <T>可以到处用(函数、接口、类型别名);
  • infer R只能在条件类型里用,必须跟着 extends
  • 没有泛型,你连「要提取的目标类型」都传不进来,infer 就没有作用对象。

我给你逐字逐句大白话拆解,结合面试话术,保证你彻底懂这行代码!完全贴合你现在的理解水平,不讲复杂术语👇

面试问题:T extends (...args: any[]) => infer R 是什么意思?

一、面试口语标准答案(直接背)

面试官您好,这行代码是TypeScript 条件类型的「类型匹配模板」

  1. extends 后面的 (...args: any[]) => infer R 是我定义的函数结构模板
  2. 作用是判断传入的泛型 T 是不是一个函数
  3. 如果 T 匹配这个函数模板,就用 infer R 自动提取出这个函数的返回值类型
  4. ...args: any[] 是为了兼容所有任意参数、任意个数的函数,保证通用性。

二、逐段拆解(秒懂版)

我们把这一串拆成 3 部分,放在 extends 后面的本质是「匹配规则」

完整结构

ts
T extends 【函数模板】 ? 提取成功返回R : 不匹配返回never

第 1 部分:(...args: any[])

= 匹配「任意函数的参数」

  • ...args:剩余参数语法,代表「不管函数有几个参数」
  • any[]:参数类型随便,不限制
  • 作用:兼容所有函数(无参、1 个参、10 个参都能匹配)

第 2 部分:=>

= 函数的固定语法,代表「参数后面是返回值」

第 3 部分:infer R

= 临时声明变量 R,捕获「函数的返回值类型」

  • 只有 T 是函数,匹配成功时,R 才会被赋值为函数的返回值类型

三、直观例子(看一遍就懂)

我们用 MyReturnType 工具类型举例,看匹配过程

ts
// 泛型T:外部传入的类型
// extends 后面:函数匹配模板
type MyReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

// 测试1:传入一个函数
type Fn = () => string;
// 1. T = Fn (是函数,匹配模板 ✅)
// 2. infer R 捕获到返回值 string → R = string
// 3. 结果:Res = string
type Res = MyReturnType<Fn>; 

// 测试2:传入非函数
type Res2 = MyReturnType<number>; 
// 1. T = number (不是函数,不匹配 ❌)
// 2. 结果:Res2 = never

四、核心总结(面试必背)

  1. extends 后面不是代码,是「类型模板」,用来判断 T 是不是函数;

  2. (...args: any[]) = 通吃所有函数参数

  3. infer R = 专门抠出函数的返回值类型

  4. 整句话的意思:

    如果 T 是任意函数,就返回它的返回值类型 R,否则返回 never


极简记忆口诀

extends 后面是函数模板...args 匹配所有参数infer R 提取返回值


我用面试标准答案 + 大白话比喻 + 核心代码 + 彻底澄清误区,把你最晕的 extends / & / 交集 / 并集 一次性讲透,这是 TS 新手最容易踩坑的点,面试官也特别爱问!

面试问题:TS 里 extends 和 & 是继承、合并、交集还是并集?

一、面试口语满分回答(直接背)

面试官您好,这里有两个核心误区必须澄清

  1. 接口的 extends类型的 &(交叉类型)作用完全一样,都是「类型合并 / 扩展」extends继承&交叉,但它们都不是数学里的「交集」,而是把多个类型的属性全部叠加在一起
  2. 只有 | 联合类型 才是数学里的并集
  3. 唯一例外:基础类型用 & 交叉,才会变成数学交集(比如 string & number = never)。

简单记:

  • extends / & = 叠加(全都要)
  • | = 选一个(二选一)

二、逐一定义 + 大白话比喻

1. interface 的 extends继承(扩展合并)

  • 属于面向对象语法,官方叫「继承」;
  • 实际效果:子接口完全拥有父接口的所有属性,再新增自己的属性
  • 比喻:儿子继承爸爸的所有财产,再自己赚新的
ts
interface Father { money: number }
// 继承:Son 拥有 Father 的所有属性 + 新增 car
interface Son extends Father { car: string }

// 最终类型:{ money: number; car: string }
const son: Son = { money: 100, car: "宝马" }

2. type 的 &交叉类型 → 本质:合并叠加

  • 这是新手最大坑TS 交叉类型 & ≠ 数学交集
  • 数学交集:只保留共有的部分
  • TS 交叉:要求同时满足所有类型,所以所有属性全部合并
  • 比喻:把两个盒子里的东西,全部倒进一个新盒子
ts
type A = { name: string }
type B = { age: number }
// 交叉&:合并 A + B 的所有属性
type C = A & B 

// 最终类型:{ name: string; age: number }
const c: C = { name: "张三", age: 18 }

3. 关键对比:extends& 对象类型下效果完全一样

ts
// 写法1:extends 继承
interface X {a:number}
interface Y extends X {b:string} // {a:number, b:string}

// 写法2:& 交叉
type X = {a:number}
type Y = X & {b:string} // {a:number, b:string}

✅ 结论:定义对象类型时,extends 和 & 就是同义词,只是语法不同


三、终极澄清:交集 / 并集 到底对应谁?

表格一眼看懂

表格

语⁠法名⁠字通⁠俗⁠理⁠解数⁠学⁠概⁠念对⁠象⁠类⁠型⁠效⁠果
extends接⁠口⁠继⁠承全⁠都⁠要合⁠并⁠所⁠有⁠属⁠性
&交⁠叉⁠类⁠型全⁠都⁠要无(基⁠础⁠类⁠型⁠才⁠是⁠交⁠集)合⁠并⁠所⁠有⁠属⁠性
``联⁠合⁠类⁠型二⁠选⁠一并⁠集满⁠足⁠其⁠一⁠即⁠可

1. 并集 = |(唯一的选一个)

ts
type Gender = "男" | "女" // 二选一,这就是并集
type Obj = {a:number} | {b:string} // 满足一个就行

2. 唯一的交集:基础类型用 &

只有string/number/boolean这种基础类型交叉,才会变成数学交集:

ts
// 数学交集:一个值不可能既是 string 又是 number → 结果 never
type ErrorType = string & number

四、面试必背总结(一句话)

  1. extends(接口)&(类型)都是合并叠加,全都要,不是交集;
  2. |并集,二选一;
  3. 只有基础类型交叉& 才等于数学交集(结果 never)。

极简口诀(面试秒答)

继承扩展用 extends,交叉合并用 &,全都想要用这俩;二选一用竖线 |,这才叫做是并集;基础类型交叉 &,变成交集是 never!

最近更新