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

TypeScript:为对象数组转属性值为键的结构定义正确类型

嘿,这个需求我熟!把对象数组转成以指定属性值为键、原对象为值的结构,TypeScript完全可以通过泛型类型定义实现类型安全的转换,下面是一套实用的方案:

核心泛型类型定义

我们可以先定义一个泛型类型RecordFromArray,它能根据输入的数组类型和指定的键属性,自动推导目标对象的类型:

type RecordFromArray<
  T extends readonly { [K in Key]: PropertyKey }[],
  Key extends keyof T[number]
> = {
  // 用as子句重映射键:取每个数组元素的Key属性值作为新对象的键
  [Item in T[number] as Item[Key]]: Item;
};

类型解释

  • T extends readonly { [K in Key]: PropertyKey }[]:约束输入的数组元素必须包含Key这个属性,且属性值是有效的键类型(PropertyKey是TypeScript内置的string | number | symbol别名,确保能作为对象键)
  • [Item in T[number] as Item[Key]]:这是TypeScript的键重映射语法,遍历数组的每个元素类型,把元素的Key属性值作为新对象的键,值则保留原元素的类型。
实际使用示例

我们用一个用户数组的例子来演示:

// 先定义基础对象类型
type User = { id: string; name: string; age: number };

// 示例数组(用const断言可以让TypeScript推导更精确的键值)
const users = [
  { id: "user1", name: "Alice", age: 30 },
  { id: "user2", name: "Bob", age: 25 },
] as const;

// 生成以id为键的对象类型
type UsersById = RecordFromArray<typeof users, "id">;

此时UsersById的类型会被精确推导为:

{
  user1: { readonly id: "user1"; readonly name: "Alice"; readonly age: 30 };
  user2: { readonly id: "user2"; readonly name: "Bob"; readonly age: 25 };
}
带类型约束的转换函数

如果需要实际的转换函数,我们可以把上面的泛型类型和函数结合,实现完全类型安全的转换:

function arrayToRecord<
  T extends readonly { [K in Key]: PropertyKey }[],
  Key extends keyof T[number]
>(array: T, key: Key): RecordFromArray<T, Key> {
  return array.reduce((acc, item) => {
    acc[item[key] as keyof typeof acc] = item;
    return acc;
  }, {} as RecordFromArray<T, Key>);
}

// 使用函数转换
const usersById = arrayToRecord(users, "id");
// usersById 的类型完全匹配UsersById,访问usersById.user1时会有完整的类型提示
注意事项
  • 如果数组中存在重复的键值,TypeScript会自动合并对应的值类型(比如两个元素的id都是"user1",但属性值不同,值类型会变成联合类型)
  • 类型约束会确保你选择的键属性一定存在于数组元素中,且属性值是合法的对象键,避免运行时出现无效键的问题

内容的提问来源于stack exchange,提问作者Tomáš Burda

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 03:27:08