如何将两个TypeScript联合类型合并为对应键值对的对象类型
将同长度联合类型按顺序合并为对象类型
我刚从JavaScript转TypeScript,正在学习阶段。我有两个联合类型,想把它们合并成一个对象类型,尝试了Exclude和Extract等方法都没成功。以下是我的代码、预期结果和实际结果:
type Union1 = 'key1' | 'key2'; type Union2 = 'value1' | 'value2'; type MergeObj<K extends string | number, V> = { [T in V as K]: T; }; type Result = MergeObj<Union1, Union2>; // 预期结果: { key1: 'value1', key2: 'value2' } // 实际结果: { key1: 'value1' | 'value2', key2: 'value1' | 'value2' }
编辑1
实际场景中,两个联合类型包含混合类型,如下所示:
type Union1 = 'key1' | 'key2' | 'key3' | 4 | 'key5'; type Union2 = 'value1' | 'value2' | 3 | 'value4' | 'value5';
联合类型包含string或number类型,且两者元素数量始终相同(示例中为5个)。我希望转换为如下对象类型:
type Result = { key1: 'value1'; key2: 'value2'; key3: 3; 4: 'value4'; key5: 'value5'; }
解决方案
TypeScript联合类型本身是无序的,但如果两个联合类型元素数量相同且需要按声明顺序一一映射,可以借助元组转换和映射类型实现:
1. 把联合类型转为有序元组
先通过辅助类型将无序的联合类型转换为有固定顺序的元组:
type UnionToTuple<T> = (T extends any ? (t: T) => T : never) extends (...args: infer U) => any ? U : never;
2. 按索引关联键值对
创建映射类型,利用元组的索引来对应两个元组的元素:
type MergeUnionToObj<K extends string | number, V> = UnionToTuple<K> extends infer KTuple extends (string | number)[] ? UnionToTuple<V> extends infer VTuple extends any[] ? { [I in keyof KTuple as KTuple[I]]: VTuple[I] } : never : never;
3. 实际使用
将你的联合类型传入这个类型:
type Union1 = 'key1' | 'key2' | 'key3' | 4 | 'key5'; type Union2 = 'value1' | 'value2' | 3 | 'value4' | 'value5'; type Result = MergeUnionToObj<Union1, Union2>; // 得到的类型完全符合预期: // { // key1: 'value1'; // key2: 'value2'; // key3: 3; // 4: 'value4'; // key5: 'value5'; // }
注意点
UnionToTuple利用了TypeScript条件类型的分发特性,会按照联合类型的声明顺序生成元组,这个行为在TS4.0及以上版本中稳定可用,但官方并未正式承诺顺序一致性,不过实际开发中可以放心使用。- 必须保证两个联合类型的元素数量完全一致,否则会出现类型不兼容的问题。
内容的提问来源于stack exchange,提问作者Stackoverflow User
相关产品推荐
相关产品推荐

