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

Typescript中如何将对象数组转换为指定键索引的对象集合

你写的代码报错的核心原因是没有约束指定key对应的属性值类型,只有string | number | symbol类型的值可以作为对象的键,当你直接用item[key]作为对象索引时,TS无法确定T[key]是合法的键类型,因此抛出类型错误。

修正后的完整实现

// PropertyKey是TS内置类型,等价于 string | number | symbol,即所有合法对象键的联合类型
const convert = <T extends Record<K, PropertyKey>, K extends keyof T>(arr: T[], key: K) => {
    // 定义返回对象类型为:键是传入key对应的值类型,值是数组的元素类型
    const result = {} as Record<T[K], T>
    arr.forEach(item => {
        result[item[key]] = item
    })
    return result
}

改动说明

  • 新增泛型参数K,用来约束传入的key必须是数组元素T的合法属性
  • 通过T extends Record<K, PropertyKey>约束T中K属性的值必须是合法的对象键类型,如果你传入的key对应的值是对象、数组等不能作为键的类型,TS会在调用阶段直接提示错误
  • 返回值使用Record<T[K], T>类型,比你原先的Collection<T>类型更精准:比如你示例中传入name作为key,返回对象的键会被自动推导为"alice" | "bob"的字面量联合类型,后续使用时能获得更完善的类型提示,避免非法键访问的错误。

使用示例

const myArr = [
    { name: "alice", id: "54dc2a", age: 23 },
    { name: "bob", id: "662adf", age: 60 }
]

// 传入name作为key
const nameMap = convert(myArr, "name")
// 自动推导nameMap类型为 Record<"alice"|"bob", {name: string; id: string; age: number}>
console.log(nameMap.alice) // 正常提示,无报错
console.log(nameMap.nobody) // TS会直接提示该键不存在,提前发现错误

// 传入id作为key也可以正常使用
const idMap = convert(myArr, "id")
// idMap类型推导为 Record<"54dc2a"|"662adf", typeof myArr[number]>

如果你需要保留之前定义的Collection类型,可以修改为如下形式兼容:

type Collection<K extends PropertyKey, T> = { [key in K]: T }

// 对应的convert实现
const convert = <T extends Record<K, PropertyKey>, K extends keyof T>(arr: T[], key: K): Collection<T[K], T> => {
    const result = {} as Collection<T[K], T>
    arr.forEach(item => {
        result[item[key]] = item
    })
    return result
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 19:54:04