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

如何修改TypeScript的ArrayBuilder类型以支持可选元素与展开语法?

TypeScript ArrayBuilder工具类型支持可选元素的修复方案

问题背景

现有ArrayBuilder工具类型可正确处理带展开(spread)标记的数组类型定义,例如Test1能生成预期的[string, ...string[], number]。但该类型未支持optional: true的元素,导致Test2当前生成[string, boolean, ...string[]],而预期结果应为[string, boolean?, ...string[]]。原实现中,展开语法[...A,...ItemToSpread]与可选属性的索引签名语法兼容存在问题,需针对性修复。

原代码实现

type Def = { type: any, spread: boolean, optional: boolean }
type A = { type: string,   spread: false, optional: false }
type B = { type: boolean,  spread: false, optional: true  }
type C = { type: string[], spread: true,  optional: false }
type D = { type: number,   spread: false, optional: false }

type ArrayBuilder<
  T extends Def[],
  A extends any[] = [],
  B extends any[] = [],
  C extends any[] = [],
  State extends 'A' | 'B' = 'A',
> = T extends [
  infer H extends Def,
  ...infer R extends Def[],
] ? State extends 'A' ? H['spread'] extends true ? ArrayBuilder<R, A, H['type'], [], 'B'> : ArrayBuilder<R, [...A, H['type']], [], [], 'A'>
  :ArrayBuilder<R, A, B, [...C, H['type']], 'B'>
  : [...A, ...B, ...C]

type Test1 = ArrayBuilder<[A,C,D]> // [string, ...string[], number]

// 需要修改上述代码,使Test2生成[string, boolean?, ...string[]]
type Test2 = ArrayBuilder<[A,B,C]> // 当前为[string, boolean, ...string[]] - 需改为[string, boolean?, ...string[]]

修复方案

通过新增辅助类型处理元素的可选性,并调整ArrayBuilder中元素拼接的逻辑,实现可选元组项的支持:

type Def = { type: any, spread: boolean, optional: boolean }
type A = { type: string,   spread: false, optional: false }
type B = { type: boolean,  spread: false, optional: true  }
type C = { type: string[], spread: true,  optional: false }
type D = { type: number,   spread: false, optional: false }

// 辅助类型:根据optional标记将元素转为可选元组项
type Optionalize<T, IsOptional extends boolean> = IsOptional extends true ? T? : T;

type ArrayBuilder<
  T extends Def[],
  A extends any[] = [],
  B extends any[] = [],
  C extends any[] = [],
  State extends 'A' | 'B' = 'A',
> = T extends [
  infer H extends Def,
  ...infer R extends Def[],
] ? State extends 'A' 
  ? H['spread'] extends true 
    ? ArrayBuilder<R, A, H['type'], [], 'B'> 
    : ArrayBuilder<R, [...A, Optionalize<H['type'], H['optional']>], [], [], 'A'>
  : ArrayBuilder<R, A, B, [...C, Optionalize<H['type'], H['optional']>], 'B'>
  : [...A, ...B, ...C]

type Test1 = ArrayBuilder<[A,C,D]> // [string, ...string[], number] - 符合预期
type Test2 = ArrayBuilder<[A,B,C]> // [string, boolean?, ...string[]] - 符合预期

修复说明

  1. 辅助类型Optionalize:根据元素的optional布尔值,将元素类型转为可选(T?)或保持原样。TypeScript元组原生支持可选项语法,无需使用索引签名的方式,避免了与展开语法的兼容问题。
  2. 调整元素拼接逻辑:在处理非spread元素(无论处于State'A'还是'B'阶段)时,使用Optionalize处理元素类型,确保可选标记被正确转换为元组中的可选项。
  3. 保留原有展开逻辑:spread元素的处理逻辑保持不变,确保...string[]这类展开类型仍能正确生成。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 06:27:37