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

TypeScript映射集合时键类型报错,如何限制pick参数为string类型?

TypeScript泛型函数索引报错:限制pick参数为string类型

问题场景

需要实现一个泛型函数,映射对象集合并提取每个对象指定成员的值。当前代码返回的结果类型符合预期,但函数内部obj[pick]处存在编译错误:

type RadioOption = {
  value: string
  label: string
}

const requestTypeOptions = [
  { value: "question", label: "I have a question" },
  { value: "problem", label: "I have a problem" },
  { value: "complaint", label: "I have a complaint" },
] as const satisfies RadioOption[];

function pickKeyValue<C extends {[k: string]: any}[], K extends keyof C[number]>(collection: C, pick: K) {
  return collection.map((obj, i) => {
    return obj[pick]
    //         ^^^^    <- 编译错误
  }) as { [I in keyof C]: C[I][K] };
}

const pickedValues = pickKeyValue(requestTypeOptions, 'value')
// pickedValues: ["question", "problem", "complaint"]

错误原因是pick的类型被推导为string | number | symbol,而{[k: string]: any}类型的对象不能用number或symbol类型的索引访问。

解决方案

方法1:通过交叉类型限制K为string类型

修改泛型约束,让K必须是string类型与C[number]键的交集,确保pick只能是string类型的属性名:

type RadioOption = {
  value: string
  label: string
}

const requestTypeOptions = [
  { value: "question", label: "I have a question" },
  { value: "problem", label: "I have a problem" },
  { value: "complaint", label: "I have a complaint" },
] as const satisfies RadioOption[];

function pickKeyValue<C extends {[k: string]: any}[], K extends string & keyof C[number]>(collection: C, pick: K) {
  return collection.map((obj) => obj[pick]) as { [I in keyof C]: C[I][K] };
}

const pickedValues = pickKeyValue(requestTypeOptions, 'value')
// pickedValues: ["question", "problem", "complaint"]

方法2:用Record<string, any>约束集合类型

将集合的泛型约束改为Record<string, any>[],Record<string, any>明确限定对象的键为string类型,因此keyof C[number]自动推导为string类型:

type RadioOption = {
  value: string
  label: string
}

const requestTypeOptions = [
  { value: "question", label: "I have a question" },
  { value: "problem", label: "I have a problem" },
  { value: "complaint", label: "I have a complaint" },
] as const satisfies RadioOption[];

function pickKeyValue<C extends Record<string, any>[], K extends keyof C[number]>(collection: C, pick: K) {
  return collection.map((obj) => obj[pick]) as { [I in keyof C]: C[I][K] };
}

const pickedValues = pickKeyValue(requestTypeOptions, 'value')
// pickedValues: ["question", "problem", "complaint"]

原理说明

  • 方法1通过string & keyof C[number]的交叉类型,过滤掉keyof返回的number和symbol类型,只保留string类型的键。
  • 方法2利用Record<string, any>的类型定义,直接约束集合中每个对象的键只能是string,从根源上确保pick参数的类型为string。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 10:25:17