You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript中Prepend和Tail类型疑问:为何用函数扩展处理数组?

解析TypeScript的Prepend和Tail类型实现逻辑

为什么用函数类型扩展处理数组?

这种写法是TypeScript早期版本的实用技巧——当时直接对数组类型做剩余元素推断的语法支持还不完善,开发者便借助函数参数的剩余参数推断能力,实现数组的前置元素拼接和尾部元素截取。虽然现在TypeScript已经支持更直观的数组扩展写法,但这类旧写法依然是类型编程技巧的典型示例,能帮你理解TypeScript类型系统的灵活特性。

函数参数的infer推断对剩余参数的处理非常精准:当把数组类型作为函数的剩余参数时,TypeScript可以完整捕获参数列表的结构,进而映射为对应的数组类型。

Prepend类型中的U是什么?

U是通过infer关键字推断出来的完整函数参数数组类型。具体逻辑如下:

  1. 先构造一个函数类型:第一个参数是要前置的元素E,剩余参数是输入数组T,即(head: E, ...args: T) => any。
  2. 用条件类型将这个函数与(...args: infer U) => any匹配——infer U会自动捕获整个函数的参数列表,也就是[E, ...T]。
  3. 最后返回U,就得到了把E前置到数组T后的新数组类型。

逐行拆解两个类型

Prepend类型

type Prepend<E, T extends any[]> =
    ((head: E, ...args: T) => any) extends ((...args: infer U) => any)
    ? U
    : T
  • 输入:待前置元素E、目标数组T
  • 核心逻辑:通过函数参数的结构映射,将E与T拼接成新数组
  • 示例验证:Prepend<number, [1,2]>生成函数(head: number, ...args: [1,2]) => any,推断出U = [number,1,2],最终返回该数组。

Tail类型

type Tail<T extends readonly any[]> = 
    ((...t:T) => any) extends ((_:any, ...tail: infer TT) => any) 
    ? TT 
    : []
  • 输入:只读数组T
  • 核心逻辑:通过忽略函数第一个参数、推断剩余参数的方式,提取数组去掉首元素后的部分
  • 示例验证:Tail<[1,2,3]>生成函数(...t: [1,2,3]) => any,匹配时TT会被推断为[2,3],最终返回该数组。

现代简化写法

现在TypeScript支持直接对数组做infer推断,这两个类型可以简化为更易读的形式:

// 简化版Prepend
type Prepend<E, T extends any[]> = [E, ...T];

// 简化版Tail
type Tail<T extends readonly any[]> = T extends [any, ...infer TT] ? TT : [];

效果和原写法完全一致,但可读性大幅提升。

内容的提问来源于stack exchange,提问作者Joe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 16:42:34