仅接受数组类型属性键的函数(推导返回类型)
解决TypeScript 2.8条件类型中提取数组属性唯一元素的问题
我懂你现在的困扰——已经能限制函数只接收对象里属于数组类型的属性,但卡在了返回类型推导和编译错误上。咱们一步步拆解解决:
第一步:先定义精准的键筛选类型
首先得把对象里所有值为数组类型的键筛选出来,用条件类型实现:
type ArrayKeys<T> = { [K in keyof T]: T[K] extends any[] ? K : never; }[keyof T];
这个类型会遍历对象T的所有键,把值不是数组的键直接排除,只留下符合要求的数组类型属性键。
第二步:编写函数并指定返回类型
接下来要让函数接收对象和对应的数组键,同时自动推导返回的元素类型。这里用infer关键字提取数组的元素类型:
function getSingleElement<T, K extends ArrayKeys<T>>( obj: T, key: K ): T[K] extends (infer U)[] ? U : never { // 业务上已经保证数组恰好有一个元素,直接取第一个元素即可 return obj[key][0] as T[K] extends (infer U)[] ? U : never; }
返回类型通过条件类型推断出数组的元素类型U,实现部分因为TypeScript无法在编译时确认数组长度,所以用类型断言绕过检查——毕竟你业务逻辑已经确保了数组只有一个元素。
第三步:测试验证
用实际场景的对象测试一下,看看效果:
interface BusinessObj { singleId: [number]; // 元组类型,明确长度为1 singleName: string[]; // 普通数组,业务上保证长度为1 status: boolean; } const data: BusinessObj = { singleId: [1001], singleName: ["TypeScript"], status: true }; // 自动推导返回类型为number const userId = getSingleElement(data, "singleId"); // 自动推导返回类型为string const userName = getSingleElement(data, "singleName"); // 编译报错:"status"不是数组类型的键,符合预期 // const err = getSingleElement(data, "status");
解释你遇到的编译错误
你之前碰到的Type number cannot be used to index type Pick<T, ...>错误,本质是TypeScript没法确认Pick后的属性值一定是数组类型。而咱们上面的写法通过K extends ArrayKeys<T>直接约束了键的范围,同时用T[K] extends (infer U)[]明确了属性值是数组,TypeScript就能正确识别可以用数字索引访问数组元素了。
如果你的场景里数组是明确长度为1的元组(比如[U]),还能进一步优化类型,让TypeScript精准知道数组有且只有一个元素,连类型断言都不用:
type SingleElementTupleKeys<T> = { [K in keyof T]: T[K] extends [infer U] ? K : never; }[keyof T]; function getSingleTupleElement<T, K extends SingleElementTupleKeys<T>>( obj: T, key: K ): T[K] extends [infer U] ? U : never { return obj[key][0]; // 元组明确有一个元素,无需断言 }
这样就完美匹配你业务中“数组恰好包含一个元素”的需求啦。
内容的提问来源于stack exchange,提问作者Motti
相关产品推荐
相关产品推荐

