You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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,符合预期

常见疑问解答

  1. 如何判断K和keyof T完全相等
    直接使用条件判断keyof T extends K即可:keyof T是原对象所有属性的联合类型,如果它是K的子类型,说明K已经覆盖了所有属性。如果要兼容T为联合类型的场景,可给两边套上元组避免分布式条件判断:[keyof T] extends [K]。

  2. 关于内置Pick类型的误区
    你之前误以为内置Pick<T, K>不符合需求是误解,它的定义就是仅生成包含K指定属性的类型,和你的实现逻辑完全匹配。如果你不需要允许访问未传入的属性,直接把返回类型的部分分支改成Pick<T, K>即可,访问未传入属性时TS会直接报错,类型安全性更高。

内容的提问来源于stack exchange,提问作者mpen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 12:15:03