TypeScript中如何将映射泛型类型转为元组联合?实现强类型Object.entries
实现强类型约束的Object.entries类型
要让Entries<T>返回每个属性键值对一一对应的二元元组联合,你需要利用TypeScript的分布式条件类型和映射类型来逐个处理对象的每个属性,而不是直接取keyof T和对应的联合值。
正确的类型定义
export type Entries<T> = { [K in keyof T]: [K, T[K]]; }[keyof T][];
效果验证
当你使用Entries<{first: number, second: string}>时,得到的类型会是:
(["first", number] | ["second", string])[]
完全符合你的预期——数组中的每个元素都是对应属性的精确键值元组,不会出现键值不匹配的情况。
为什么原来的实现不行?
原来的[keyof T, T[keyof T]][]会把keyof T解析成所有键的联合类型,T[keyof T]解析成所有值的联合类型,两者是独立的,所以最终会得到(键联合, 值联合)的元组数组,导致可能出现["first", string]这种不符合实际的类型组合。
拆解实现逻辑
- 首先用映射类型
{ [K in keyof T]: [K, T[K]] }遍历T的每个属性K,为每个属性生成对应的[键, 值]元组类型,得到一个新的对象类型。比如对于{first: number, second: string},这个映射后的类型是:{ first: ["first", number]; second: ["second", string]; } - 然后通过
[keyof T]索引这个对象类型,取出所有属性值的联合类型,也就是["first", number] | ["second", string]; - 最后加上
[]把这个联合类型变成数组,就得到了每个元素都是精确键值对的数组类型。
额外优化:处理可选属性
如果你的对象包含可选属性,上面的类型会把可选属性的元组也包含进来,但值可能是undefined。这里提供两种常见的处理方式:
过滤可选属性
export type Entries<T> = { [K in keyof T]-?: [K, T[K]]; }[keyof T][];
这里的-?是移除属性的可选标记,确保每个元组的值都是非undefined的(前提是原属性的类型本身不包含undefined),这更贴近Object.entries的实际运行时行为——未赋值的可选属性不会被遍历到。
保留可选属性并明确值类型
如果你想保留可选属性,但让值类型明确包含undefined,可以用:
export type Entries<T> = { [K in keyof T]: [K, Required<T>[K] | undefined]; }[keyof T][];
内容的提问来源于stack exchange,提问作者Ritave
相关产品推荐
相关产品推荐

