如何在TypeScript中实现具备类型安全的pluck函数?
嘿,我之前也折腾过这个类型安全的pick函数,咱们来搞定它~
你参考的那个类型签名方向是完全对的,可能是你在写函数体的时候没处理好类型断言,或者忽略了TS运行时和类型系统的差异。下面是可以直接用的完整实现:
完整的类型安全pick函数实现
function pick<T, K extends keyof T>(obj: T, ...keys: K[]): Pick<T, K> { // 初始化结果对象,用Pick<T, K>断言类型,告诉TS后续会填充正确属性 const result = {} as Pick<T, K>; // 遍历传入的key,逐个从原对象提取属性 keys.forEach(key => { result[key] = obj[key]; }); return result; }
为什么这么写?
- 类型约束:
K extends keyof T确保你传入的所有keys都是原对象obj的有效属性名,编译时就会阻止你传入不存在的key(比如pick(obj, 'd')会直接报错),完美保证类型安全。 - 返回值类型:用TS内置的
Pick<T, K>工具类型,自动帮我们生成只包含指定属性的新类型,完全符合你想要的{a:1, b:2}对应的类型{a: number; b: number}。 - 运行时处理:因为TS的类型信息在运行时会被擦除,所以我们需要手动遍历keys并复制属性,这里用类型断言
as Pick<T, K>是因为初始空对象{}不满足返回值类型的结构,需要明确告诉TS我们后续会把它填充成符合要求的对象。
测试你的例子
const obj = {a:1, b: 2, c: 3}; const plucked = pick(obj, 'a', 'b'); // plucked的类型是{ a: number; b: number; },值是{ a: 1, b: 2 },完全符合预期!
兼容旧TS版本(如果需要)
如果你的TS版本低于2.1(Pick工具类型是2.1才加入的),可以手动实现Pick类型:
// 手动实现Pick工具类型 type Pick<T, K extends keyof T> = { [P in K]: T[P]; }; // 然后再写pick函数,和上面一样 function pick<T, K extends keyof T>(obj: T, ...keys: K[]): Pick<T, K> { const result = {} as Pick<T, K>; keys.forEach(key => { result[key] = obj[key]; }); return result; }
这样应该就能解决你编译不通过的问题啦~
内容的提问来源于stack exchange,提问作者Ruan Mendes
相关产品推荐
相关产品推荐

