TypeScript中如何指定泛型K恰好等于keyof T以优化pick函数类型?
解决方案
这个需求完全可以实现,核心是通过条件类型判断传入的key是否覆盖了原对象的所有属性,再返回对应的类型。
优化后的完整实现
type PickResult<T, K extends keyof T> = // 判断是否传入了所有key keyof T extends K ? T // 传入所有key直接返回原类型 // 只传部分key的情况:传入的key保留原类型,未传入的类型为undefined : Pick<T, K> & Partial<Record<Exclude<keyof T, K>, undefined>> // TS 5.0+ 支持const类型参数,可自动捕获keys的字面量类型 export function pick<T, const K extends keyof T>(obj: T, keys: K[]): PickResult<T, K> { const ret = Object.create(null) for(const key of keys) { ret[key] = obj[key] } return ret as PickResult<T, K> }
版本兼容说明
如果你的TS版本低于5.0,不支持const类型参数,调用时需要给keys加as const断言,保证TS能推断出准确的字面量联合类型:
const partial = pick(user, ['id', 'name'] as const)
测试验证
interface User { id: number name: string age: number } const user: User = { id: 1, name: '张三', age: 20 } // 传入所有key,返回值类型为User const fullUser = pick(user, ['id', 'name', 'age']) console.log(fullUser.age) // 类型为number // 传入部分key const partialUser = pick(user, ['id', 'name']) console.log(partialUser.id) // 类型为number console.log(partialUser.age) // 类型为undefined,符合预期
常见疑问解答
如何判断K和keyof T完全相等
直接使用条件判断keyof T extends K即可:keyof T是原对象所有属性的联合类型,如果它是K的子类型,说明K已经覆盖了所有属性。如果要兼容T为联合类型的场景,可给两边套上元组避免分布式条件判断:[keyof T] extends [K]。关于内置Pick类型的误区
你之前误以为内置Pick<T, K>不符合需求是误解,它的定义就是仅生成包含K指定属性的类型,和你的实现逻辑完全匹配。如果你不需要允许访问未传入的属性,直接把返回类型的部分分支改成Pick<T, K>即可,访问未传入属性时TS会直接报错,类型安全性更高。
内容的提问来源于stack exchange,提问作者mpen
相关产品推荐
相关产品推荐

