TypeScript类型实现优化:键数组与值数组转对应对象的更优方案咨询
优化TypeScript中从两个数组生成键值对象类型的实现
问题描述
我想要创建一个TypeScript类型,接收两个数组作为输入:比如Keys数组示例为["foo", "bar", "baz"],Values数组示例为[50, number, "abc"],最终输出由这些键值对组成的对象类型{ foo: 50, bar: number, baz: "abc" }。
我当前的实现代码如下:
type UnionToIntersection<T> = (T extends object ? (k: T) => void : never) extends (k: infer U) => void ? U : never; type KeyValuePairsFromLists< Keys extends Array<string | number>, Values extends Array<any> > = { [index in keyof Keys]: index extends keyof Values ? [Keys[index], Values[index]] : never; }; type ObjectFromKeyValuePairs< KV extends Array<[string | number, any]>, T = { [index in keyof KV]: KV[index] extends [string | number, any] ? Record<KV[index][0], KV[index][1]> : never; } > = UnionToIntersection<T[keyof T]>; type ObjectFromKeyValueArrays< Keys extends Array<string | number>, Values extends Array<any> > = ObjectFromKeyValuePairs<KeyValuePairsFromLists<Keys, Values>>; const myObj = {} as ObjectFromKeyValueArrays< ["foo", "bar"], [5, "bar"] >; type foo = typeof myObj.foo // 5 type bar = typeof myObj.bar // string
我的实现逻辑是先将两个数组转换为键值对数组,再将其映射为单键对象的联合类型,最后将联合类型转换为交叉类型以得到最终对象。请问是否存在更优的实现方式?当前的实现是否存在问题?
更优的实现方案
在TypeScript 4.1+中,我们可以利用映射类型重映射(as子句)直接实现这个需求,不需要经过联合转交叉的繁琐步骤,代码更简洁高效:
type ObjectFromKeyValueArrays< Keys extends readonly (string | number)[], Values extends readonly any[] > = { // 过滤元组的非数字索引(比如length、push等),将索引转换为对应的键名 [I in keyof Keys as I extends `${number}` ? Keys[I] : never]: // 取Values对应索引的类型,确保索引在有效范围内 Values[I & keyof Values] };
代码解释:
- 使用
I extends${number}``过滤掉元组自带的length、push等非数字属性,只保留对应元素的数字索引 - 通过
as子句将元组的数字索引直接重映射为Keys数组中对应位置的键名 - 直接通过
Values[I & keyof Values]获取Values数组对应位置的值类型,类型关联更直接
测试一下这个实现:
const myObj = {} as ObjectFromKeyValueArrays<["foo", "bar"], [5, "bar"]>; type foo = typeof myObj.foo; // 5(保留字面量类型) type bar = typeof myObj.bar; // "bar"(比原实现更准确,原实现会推断为string) // 当两个数组长度不一致时,会清晰提示类型问题 type MismatchExample = ObjectFromKeyValueArrays<["a", "b"], [1]>; // 得到 { a: 1, b: never },明确显示第二个键对应的值类型不存在
原实现的潜在问题
- 步骤冗余,可读性差:原实现需要经过三层中间类型转换,逻辑绕弯,新接触的开发者很难快速理解实现思路
- 类型准确性不足:原实现中
Values数组的字面量类型会被拓宽为基础类型(比如"bar"会变成string),而优化后的实现会保留字面量类型,类型更精准 - 性能与类型安全问题:联合转交叉的
UnionToIntersection在处理大量键值对时,类型推断的性能会下降;同时当Keys和Values长度不一致时,原实现会生成包含never的交叉类型,最终可能隐藏类型不匹配的问题,而优化后的实现会直接暴露never类型,更便于排查
内容的提问来源于stack exchange,提问作者tacheometry
相关产品推荐
相关产品推荐

