如何修复TypeScript中Object.fromEntries定义以支持联合类型键?
修复TypeScript中Object.fromEntries的联合类型键推断问题
之前为Object.fromEntries定义了如下类型声明,在元组首元素为唯一类型时可以正常工作,但当元组首元素是联合类型时会推断失败:
declare global { interface ObjectConstructor { fromEntries< A extends ReadonlyArray<readonly [PropertyKey, any]> >(array: A): { [K in A[number][0]]: Extract<A[number], readonly [K, any]>[1] } } }
示例代码及问题表现:
const x = Object.fromEntries( [['a', 1], ['b', 2], ['c', 'foo']] as (['a' | 'b', number] | ['c', string])[] ); // 错误推断结果:typeof x = { a: never, b: never; c: string; }
问题根源在于,当遍历A[number][0]中的单个键(比如'a'或'b')时,Extract<A[number], readonly [K, any]>无法匹配['a' | 'b', number]这个联合元组——因为'a' | 'b'并不继承自单个的'a'或'b',导致对应值类型被推断为never。
解决方案
通过分布式条件类型遍历每个联合元组成员,先将每个元组转换为单个键值对对象,再合并这些对象类型,修复后的声明如下:
declare global { interface ObjectConstructor { fromEntries< T extends readonly [PropertyKey, unknown][] >(entries: T): MergeUnion<{ [U in T[number]]: U extends readonly [infer K, infer V] ? { [P in K]: V } : never }> } } // 辅助类型:合并联合类型中的多个对象类型 type MergeUnion<T> = T extends infer U ? { [K in keyof U]: U[K] } : never;
原理说明
- 利用TypeScript的分布式特性遍历输入元组数组的每个联合成员
U; - 对每个
U提取键K和值V,生成单个键值对的对象类型{ [P in K]: V }; - 通过
MergeUnion将所有单个键值对对象合并为完整的目标对象类型。
用原示例测试,现在可以得到正确的推断结果:
const x = Object.fromEntries( [['a', 1], ['b', 2], ['c', 'foo']] as (['a' | 'b', number] | ['c', string])[] ); // 正确推断结果:typeof x = { a: number; b: number; c: string; }
内容的提问来源于stack exchange,提问作者dx_over_dt
相关产品推荐
相关产品推荐

