You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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 },明确显示第二个键对应的值类型不存在

原实现的潜在问题

  1. 步骤冗余,可读性差:原实现需要经过三层中间类型转换,逻辑绕弯,新接触的开发者很难快速理解实现思路
  2. 类型准确性不足:原实现中Values数组的字面量类型会被拓宽为基础类型(比如"bar"会变成string),而优化后的实现会保留字面量类型,类型更精准
  3. 性能与类型安全问题:联合转交叉的UnionToIntersection在处理大量键值对时,类型推断的性能会下降;同时当Keys和Values长度不一致时,原实现会生成包含never的交叉类型,最终可能隐藏类型不匹配的问题,而优化后的实现会直接暴露never类型,更便于排查

内容的提问来源于stack exchange,提问作者tacheometry

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 13:38:15