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
相关产品推荐
相关产品推荐

