如何确保数组包含联合类型所有类型?TypeScript类型校验问题
实现联合类型转全成员元组的类型校验
没问题!要实现让数组必须包含联合类型的所有成员,咱们可以用TypeScript的高级类型技巧来定义UnionToTuple。先明确下需求:我们需要一个类型工具,把联合类型转成包含该联合所有成员的元组——也就是说,数组必须覆盖联合的每一个类型,少一个都会报类型错误,顺序倒是不强制。
核心思路
TypeScript的联合类型本身是无序且自动去重的,所以我们要做的是“收集”联合里的每一个成员,把它们拼成元组。这里会用到两个关键特性:
- 分布式条件类型:当条件类型作用于联合类型时,会自动拆分联合的每个成员单独处理。
- 交叉类型的函数推断:通过把联合成员转成函数类型的交叉,再推断出返回值,从而逐个提取联合成员。
具体实现代码
// 辅助类型:把联合类型转成交叉类型 type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never; // 核心类型:把联合类型转成包含所有成员的元组 type UnionToTuple<U> = UnionToIntersection<U extends any ? () => U : never> extends () => infer T ? [...UnionToTuple<Exclude<U, T>>, T] : [];
测试示例
咱们用你定义的Colors联合类型来测试:
type Colors = 'red' | 'blue' | 'pink'; // ❌ 错误:缺少'pink',类型不匹配 const colors1: UnionToTuple<Colors> = ['red', 'blue']; // ✅ 正确:包含所有联合成员 const colors2: UnionToTuple<Colors> = ['red', 'blue', 'pink']; // ✅ 正确:顺序不影响,只要全包含就行 const colors3: UnionToTuple<Colors> = ['pink', 'red', 'blue'];
简单解释下类型逻辑
UnionToIntersection:先把联合的每个成员转成“参数为该成员的函数”,再把这些函数转成交叉类型。最后通过infer提取出交叉函数的参数类型,得到联合类型的交叉形式——这一步是为了后续能逐个提取成员。UnionToTuple:把联合的每个成员转成“返回该成员的函数”,再转成交叉类型。通过infer提取这个交叉函数的返回值(也就是联合的某一个成员),然后用Exclude去掉已经提取的成员,递归处理剩下的部分,直到联合类型为空,最后把所有成员拼接成元组。
注意事项
- 这个实现支持TS 4.0及以上版本,低版本可能会有兼容性问题。
- 元组的顺序不一定和你定义联合类型的顺序一致,因为TypeScript的联合类型本身是无序的,但只要所有成员都包含在内就符合要求。
- 如果联合类型里有重复成员(比如
'red' | 'red' | 'blue'),生成的元组会自动去重,因为联合类型本身会去重。
内容的提问来源于stack exchange,提问作者Samuel
相关产品推荐
相关产品推荐

