如何实现TypeScript元组联合的‘反分布’转换?
TypeScript实现元组联合类型的“反分布”转换
我有一组不同长度的元组联合类型:
type Input = | [a, b, c] | [d, e] | [f, g]
想要对它们做“反分布”处理,转换成单个元组。转换后的元组中,每个位置的元素是所有输入元组对应位置元素的交集:
Transform<Input> // [a & d & f, b & e & g, c]
更多示例
- 合并对象
// 合并对象 Transform<[ { foo: 1 } ] | [ { bar: 2 } ]> // [ { foo: 1, bar: 2 } ]
- 忽略标签
// 忽略标签 Transform<[x: { foo: 1 } ] | [ y: { bar: 2 } ]> // [ { foo: 1, bar: 2 } ]
- 元素为never的情况
// 合适时元素可设为never Transform<[ number ] | [ string ]> // [ never ]
- 支持数组类型
// 支持数组类型 Transform<{ foo: 1 }[] | { bar: 2 }[]> // { foo: 1, bar: 2 }[]
- 支持扩展运算符
// 支持扩展运算符 Transform<[ { foo: 1 }, ...{ baz: 3 }[] ] | [ { bar: 2 }, ...{ boo: 4 }[] ]> // [ { foo: 1, bar: 2 }, ...{ baz: 3, boo: 4 }[] ]
- 空元组处理
// 支持空元组 Transform<[]> // []
- 单个元组处理
// 支持单个元组 Transform<[ 'a' ]> // [ 'a' ]
实现方案
通过递归遍历元组位置、收集对应类型取交集,同时处理扩展运算符对应的剩余元素部分:
// 拆分元组为固定元素部分和剩余数组部分 type SplitTuple<T> = T extends [...infer Fixed, ...infer Rest extends any[]] ? { fixed: Fixed; rest: Rest } : { fixed: []; rest: never[] }; // 对一组类型取交集 type IntersectAll<T> = T extends [infer First, ...infer Rest] ? First & IntersectAll<Rest> : unknown; // 获取元组长度 type MaxLength<T extends any[]> = T extends { length: infer L } ? L : 0; // 获取所有元组固定部分的最大长度 type GetMaxFixedLength<T> = T extends any ? MaxLength<SplitTuple<T>['fixed']> : 0; type MaxFixedLength<T> = GetMaxFixedLength<T> extends infer M ? M : 0; // 生成索引范围,用于遍历元组的每个位置 type Range<N extends number, Acc extends number[] = []> = Acc['length'] extends N ? Acc : Range<N, [...Acc, Acc['length']]>; // 获取指定索引位置的类型,不存在则返回unknown type GetTupleElement<T, Index extends number> = T extends any[] ? Index extends keyof T ? T[Index] : unknown : unknown; // 处理固定元素部分:每个位置取所有元组对应位置的类型交集 type ProcessFixedPart<T, Indices extends number[]> = { [I in Indices[number]]: IntersectAll<T extends any ? GetTupleElement<SplitTuple<T>['fixed'], I> : never>; }; // 处理剩余数组部分:取所有剩余数组元素类型的交集 type ProcessRestPart<T> = IntersectAll<T extends any ? SplitTuple<T>['rest'][number] : never>[]; // 合并固定部分和剩余部分,生成最终元组 type Transform<T> = T extends any[] ? SplitTuple<T>['rest'] extends never[] ? T // 单个元组直接返回 : ( ProcessFixedPart<T, Range<MaxFixedLength<T>>> extends infer Fixed ? ProcessRestPart<T> extends infer Rest ? Rest extends never[] ? Fixed : [...Fixed, ...Rest] : never : never ) : never;
验证实现
用示例测试上述类型:
// 基础案例 type Input1 = [a, b, c] | [d, e] | [f, g]; type Result1 = Transform<Input1>; // [a & d & f, b & e & g, c] // 合并对象 type Result2 = Transform<[ { foo: 1 } ] | [ { bar: 2 } ]>; // [ { foo: 1 } & { bar: 2 } ] // 忽略标签 type Result3 = Transform<[x: { foo: 1 } ] | [ y: { bar: 2 } ]>; // [ { foo: 1 } & { bar: 2 } ] // 元素为never type Result4 = Transform<[ number ] | [ string ]>; // [ never ] // 数组类型 type Result5 = Transform<{ foo: 1 }[] | { bar: 2 }[]>; // ({ foo: 1 } & { bar: 2 })[] // 扩展运算符 type Result6 = Transform<[ { foo: 1 }, ...{ baz: 3 }[] ] | [ { bar: 2 }, ...{ boo: 4 }[] ]>; // [ { foo: 1 } & { bar: 2 }, ...({ baz: 3 } & { boo: 4 })[] ] // 空元组 type Result7 = Transform<[]>; // [] // 单个元组 type Result8 = Transform<[ 'a' ]>; // [ 'a' ]
内容的提问来源于stack exchange,提问作者Markus
相关产品推荐
相关产品推荐

