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

如何实现适用于数组/元组的TypeScript Pick等效工具类型?

实现适用于数组/元组的Pick工具类型

TypeScript内置的Pick<T, K>是为对象设计的,直接作用于元组时会返回带数字索引的对象类型,而非预期的元组结构。下面提供两种实现方案,满足不同场景需求:

基础方案:生成联合类型数组

适合只需要元素类型集合,不严格要求元组顺序的场景:

// 提取元组的所有数字索引(排除数组原型属性)
type TupleIndices<T extends readonly any[]> = Exclude<keyof T, keyof any[]>;

// 筛选出目标索引集合中的元组索引
type FilteredIndices<T extends readonly any[], K extends number> = 
  TupleIndices<T> extends infer I ? I extends K ? I : never : never;

// 生成包含指定索引元素的数组类型
type TuplePick<T extends readonly any[], K extends number> = 
  { [P in FilteredIndices<T, K>]: T[P] } extends { [key: number]: infer V } 
    ? V[] 
    : never;

使用示例

type Foo = [a: 'a', b: 'b', c: 'c'];
type Bar = TuplePick<Foo, 1 | 2>; // 类型为 ('b' | 'c')[]
const bar: Bar = ['b', 'c']; // 合法
const invalidBar: Bar = ['a', 'b']; // 类型错误

进阶方案:生成严格顺序的元组类型

如果需要保留元组的原始顺序、元素标签和精确字面量类型,使用递归遍历实现:

type TuplePick<
  T extends readonly any[],
  K extends number,
  _CurrentIndex extends any[] = [], // 追踪当前遍历的索引位置
  _Result extends any[] = [] // 收集符合条件的元素
> = T extends [infer First, ...infer Rest]
  ? _CurrentIndex['length'] extends K
    // 当前索引命中目标,加入结果集后继续遍历
    ? TuplePick<Rest, K, [..._CurrentIndex, unknown], [..._Result, First]>
    // 当前索引未命中,继续遍历剩余元素
    : TuplePick<Rest, K, [..._CurrentIndex, unknown], _Result>
  : _Result;

使用示例

type Foo = [a: 'a', b: 'b', c: 'c'];
type Bar = TuplePick<Foo, 1 | 2>; // 精确类型:[b: 'b', c: 'c']
const bar: Bar = ['b', 'c']; // 完全合法
const wrongBar: Bar = ['c', 'b']; // 类型错误,顺序不匹配

核心逻辑说明

  • 基础方案:通过提取元组的数字索引,筛选目标索引后映射为元素类型,最终转换为数组类型。
  • 进阶方案:递归遍历元组的每个元素,通过追踪当前索引位置,收集符合目标索引的元素,生成严格匹配顺序的元组类型。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 19:00:29