TypeScript中约束pick函数选值后keys参数的可选属性
解决TypeScript Pick工具函数的重复key与智能提示问题
问题分析
你实现的pick函数能正确推导返回类型,但存在两个痛点:
- 允许传入重复的key,TypeScript不会报错
- 输入数组参数时,智能提示始终显示所有key,无法自动排除已选择的项
下面分两种场景给出解决方案:
方案1:数组参数版(解决重复key问题)
通过定义Unique辅助类型,约束keys数组的元素必须唯一,同时保留原函数的数组参数调用方式:
// 辅助类型:确保元组元素无重复 type Unique<T extends readonly any[]> = T extends [infer First, ...infer Rest] ? First extends Rest[number] ? never // 存在重复元素,返回never触发类型报错 : [First, ...Unique<Rest>] : T; const pick = <T extends object, K extends readonly (keyof T)[]>( obj: T, // 约束keys必须是无重复的元组,否则类型报错 keys: K extends Unique<K> ? K : never ): Pick<T, K[number]> => { if (!obj) return {} as Pick<T, K[number]>; return keys.reduce((acc, key) => { return { ...acc, [key]: obj[key] }; }, {} as Pick<T, K[number]>); }; // 测试用例 const user = { name: 'Alice', age: 25, email: 'alice@example.com' }; pick(user, ['name', 'age']); // ✅ 正常 pick(user, ['name', 'age', 'age']); // ❌ TypeScript报错:类型不匹配
原理
Unique类型通过递归遍历元组,检查每个元素是否在剩余元素中存在,若存在则返回never,触发类型错误- 函数泛型约束
K extends Unique<K>确保只有无重复的keys数组才能通过类型检查
方案2:柯里化版(解决重复key+智能提示问题)
如果需要实现「输入一个key后,智能提示剩余未选key」的效果,必须用柯里化方式,让每次选择key后,返回的函数自动排除已选的key:
// 辅助类型:计算剩余可选的key type RemainingKeys<T extends object, Selected extends keyof T = never> = Exclude<keyof T, Selected>; const pick = <T extends object>(obj: T) => { // 递归构造选择器 const createPicker = <Selected extends keyof T>(selected: Selected[]) => { type AvailableKeys = RemainingKeys<T, Selected[number]>; return { // 选择下一个key,返回新的选择器 pick: <K extends AvailableKeys>(key: K) => { return createPicker([...selected, key] as const); }, // 完成选择,返回最终的Pick结果 done: () => { return selected.reduce((acc, key) => ({ ...acc, [key]: obj[key] }), {} as Pick<T, Selected[number]>); } }; }; return createPicker([]); }; // 测试用例 const user = { name: 'Alice', age: 25, email: 'alice@example.com' }; // 调用方式:链式选择,每次pick后智能提示剩余未选key const pickedUser = pick(user).pick('name').pick('age').done(); // pickedUser类型为 { name: string; age: number } // 若重复选择已选key,TypeScript会报错:类型不在AvailableKeys中
原理
- 柯里化函数每次接收一个key后,通过
RemainingKeys类型排除已选的key,更新下一次可选的key集合 - 递归调用
createPicker,每次传递已选的key数组,确保后续的pick方法只能提示剩余未选的key - 最终调用
done方法,执行实际的属性提取逻辑
内容的提问来源于stack exchange,提问作者MailHunter99
相关产品推荐
相关产品推荐

