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

求实现面向元组的PickTuple与OmitTuple TypeScript工具类型

实现TypeScript元组工具类型:PickTuple与OmitTuple

问题背景

需要实现针对元组的PickTuple和OmitTuple工具类型,替代对象类型的原生Pick/Omit,要求保留元组标签,最好支持可选元组、剩余元组等复杂场景。

原实现的问题

自行编写的PickTuple返回对象类型而非元组:

export type Indices<T extends any[]> = Exclude<
  keyof T,
  keyof any[]
> extends `${infer I extends number}`
  ? I
  : never;

type Tuple = [unknown, ...unknown[]]; 

type PickTuple<T extends Tuple, K extends Indices<T>> = {
  [P in K]: T[P];
};

type Example = [one: number, two: string];
type Result = PickTuple<Example, 1>; // 结果:{ 1: string }

原因:使用对象字面量的映射类型{ [P in K]: T[P] }时,TypeScript会将其解析为对象而非元组。元组需要通过数组特定的映射方式生成。


实现方案

1. 先定义Indices类型(获取元组的数字索引)

该类型用于提取元组的所有数字索引,排除数组原型上的方法(如push、length等):

export type Indices<T extends any[]> = Exclude<
  keyof T,
  keyof any[]
> extends `${infer I extends number}`
  ? I
  : never;

2. PickTuple实现(保留元组标签)

支持单个索引或索引数组作为参数,返回对应元素组成的元组并保留原标签:

type PickTuple<T extends any[], K extends Indices<T> | readonly Indices<T>[]> =
  // 处理索引数组的情况
  K extends readonly Indices<T>[]
    ? (T extends any ? { [P in keyof K]: T[K[P]] } : never) extends infer U
      ? U extends any[] ? U : never
      : never
    // 处理单个索引的情况
    : [T[K]];

解释:

  • 当K是索引数组时,通过映射{ [P in keyof K]: T[K[P]] }构造元组:由于K是数字索引数组,keyof K为数字类型,TypeScript会自动将映射结果解析为元组而非对象,同时保留原元组的标签。
  • 当K是单个索引时,直接返回[T[K]],TypeScript会保留该元素的元组标签。

测试示例:

type Example = [one: number, two: string, three: boolean];
type PickSingle = PickTuple<Example, 1>; // [two: string]
type PickMultiple = PickTuple<Example, [0, 2]>; // [one: number, three: boolean]

// 支持可选元组
type OptionalTuple = [a: number, b?: string];
type PickOptional = PickTuple<OptionalTuple, 1>; // [b?: string | undefined]

3. OmitTuple实现(保留元组标签)

基于PickTuple实现,先计算需要保留的索引,再传入PickTuple生成结果:

type OmitTuple<T extends any[], K extends Indices<T> | readonly Indices<T>[]> =
  K extends readonly Indices<T>[]
    ? PickTuple<T, Exclude<Indices<T>, K[number]>>
    : PickTuple<T, Exclude<Indices<T>, K>>;

解释:

  • 当K是索引数组时,用Exclude<Indices<T>, K[number]>获取所有需要保留的索引(排除掉要省略的索引)。
  • 当K是单个索引时,用Exclude<Indices<T>, K>获取保留索引。
  • 最终将保留索引传入PickTuple,得到省略指定元素后的元组,自然保留原标签。

测试示例:

type Example = [one: number, two: string, three: boolean];
type OmitSingle = OmitTuple<Example, 1>; // [one: number, three: boolean]
type OmitMultiple = OmitTuple<Example, [0, 2]>; // [two: string]

// 支持剩余元组
type RestTuple = [x: number, y: string, ...rest: boolean[]];
type OmitRest = OmitTuple<RestTuple, 0>; // [y: string, ...rest: boolean[]]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 18:09:50