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

如何基于传入元组收窄TypeScript模板字面量生成的联合类型?

问题描述

我有一个通过模板字面量类型生成的联合类型,该模板字面量基于包含两个字符串的联合类型构建,会生成所有可能的排列组合。现在这个类型是通过一个接收元组数组的泛型函数定义的,请问能不能根据传入函数的元组值来收窄这个联合类型,只保留元组对应的组合?

示例代码:

function get<T extends string, K extends string>(vals: [T, K][]) {
  type FullKey = `${T}${K}`
  const answer: FullKey[] = []

  for(const v of vals) {
    const fullKey: FullKey = `${v[0]}${v[1]}`
    answer.push(fullKey)
  }

  return answer
}

const answer = get([['1', 'a'], ['2', 'b']])
//     ^?
// 如何让它的类型变成 ('1a' | '2b')[] 而不是全部排列组合的联合?
解决方案

要实现这个需求,核心是让TypeScript追踪数组中每个元组的具体配对关系,而非将所有T和K的组合无差别枚举。下面提供两种可行的实现方式:

方法一:元组数组泛型 + 映射类型

修改函数泛型定义,让它捕获整个输入数组的元组结构,再通过映射类型生成精确的拼接结果:

function get<T extends [string, string][]>(vals: [...T]) {
  // 遍历数组每个索引,拼接对应元组的两个元素
  type FullKey = { [I in keyof T]: `${T[I][0]}${T[I][1]}` }[number]
  const answer: FullKey[] = []

  for (const v of vals) {
    answer.push(`${v[0]}${v[1]}` as FullKey)
  }

  return answer
}

const answer = get([['1', 'a'], ['2', 'b']])
// answer 的类型自动推断为 ('1a' | '2b')[]

关键细节

  • T extends [string, string][]:让泛型捕获输入数组的具体元组结构(比如[["1","a"], ["2","b"]]),而非模糊的[string, string][]。
  • [...T]:强制TypeScript将输入推断为元组类型,保留每个元素的具体值信息,避免被推断为普通数组。
  • 映射类型{ [I in keyof T]: ... }[number]:遍历元组的每个索引,将对应位置的元组元素拼接成模板字面量,最后提取所有拼接结果的联合类型。

方法二:分布式条件类型(适配复杂场景)

如果需要处理嵌套或动态生成的元组数组,可以用分布式条件类型逐个处理每个元组:

// 将单个元组转换为拼接字符串类型
type TupleToKey<T extends [string, string]> = `${T[0]}${T[1]}`
// 将元组数组转换为所有拼接结果的联合类型
type ArrayToKeys<T extends [string, string][]> = 
  T extends Array<infer U> ? U extends [string, string] ? TupleToKey<U> : never : never

function get<T extends [string, string][]>(vals: [...T]): ArrayToKeys<T>[] {
  return vals.map(v => `${v[0]}${v[1]}` as ArrayToKeys<T>)
}

const answer = get([['1', 'a'], ['2', 'b']])
// answer 的类型为 ('1a' | '2b')[]

原理说明

分布式条件类型会自动遍历数组中的每个元组类型U,将其传入TupleToKey转换为对应的拼接字符串,最终汇总成所有合法配对的联合类型,完美匹配输入元组的实际组合。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 13:16:00