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

使用TypeScript泛型实现无重复字符串消费类型

TypeScript泛型实现无重复全排列数组类型限制

需求说明

需要实现一种TypeScript泛型类型,用于约束字符串数组满足以下要求:

  • 必须包含指定联合类型的所有字符串值
  • 数组中不能有重复元素
  • 支持元素的任意排列(如["month", "day", "year"]是合法的)

比如对于联合类型"year" | "month" | "day",普通的Array<"year" | "month" | "day">无法阻止重复值(如["year", "year", "year"])或缺少元素的情况,需要通过泛型解决这个问题。

实现方案

我们可以利用TypeScript的递归泛型和条件类型,跟踪已使用的元素,确保数组包含所有目标元素且无重复:

1. 辅助类型:获取联合类型的元素数量

首先需要一个辅助类型来计算联合类型的元素个数,用于后续判断是否已包含所有元素:

type LengthOfUnion<T, Accumulator extends any[] = []> = 
  T extends never ? Accumulator['length'] : LengthOfUnion<Exclude<T, T>, [...Accumulator, T]>;

2. 核心泛型类型:UniqueFullTuple

定义核心泛型UniqueFullTuple,通过递归逐步"消费"联合类型中的元素,确保无重复且全量使用:

type UniqueFullTuple<T extends string, Used extends string[] = []> = 
  // 当已使用元素的联合类型等于目标T时,返回当前数组类型
  Used[number] extends T ? Used :
  // 否则,仅允许选择T中未被使用的元素,递归构建数组
  { [K in T]: [K, ...UniqueFullTuple<Exclude<T, K>, [...Used, K]>] }[T];

3. 使用示例

// 定义目标联合类型
type DateParts = "year" | "month" | "day";

// 合法的全排列数组
const validOrder1: UniqueFullTuple<DateParts> = ["year", "month", "day"];
const validOrder2: UniqueFullTuple<DateParts> = ["month", "day", "year"];
const validOrder3: UniqueFullTuple<DateParts> = ["day", "year", "month"];

// 以下情况会触发TypeScript类型错误:
const duplicateError: UniqueFullTuple<DateParts> = ["year", "year", "day"]; // 存在重复元素
const missingError: UniqueFullTuple<DateParts> = ["year", "month"]; // 缺少元素
const extraError: UniqueFullTuple<DateParts> = ["year", "month", "day", "hour"]; // 包含多余元素

原理说明

  • 递归逻辑:每次从联合类型T中选择一个未被使用的元素K,通过Exclude<T, K>移除已选元素,将K加入已使用数组Used,继续递归处理剩余元素。
  • 终止条件:当Used[number](已使用元素的联合类型)等于目标T时,说明所有元素都已被使用,返回当前的数组类型。
  • 类型约束:通过索引类型{ [K in T]: ... }[T],确保只能选择T中未被使用的元素,从而避免重复。

内容的提问来源于stack exchange,提问作者cyan-kinesin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 16:52:29