如何编写TypeScript泛型函数获取继承HasID接口的对象属性?
解决TypeScript泛型函数校验对象属性是否继承HasID的问题
我来帮你搞定这个需求!你想要实现一个泛型函数,只有当传入的对象属性符合HasID接口时才允许调用,否则报错。你的思路是对的,但原来的类型约束写法有问题,导致TypeScript无法正确推断O[K]和T的关系,所以出现了赋值错误。
下面是正确的实现方案,我会一步步拆解说明:
第一步:定义基础接口和辅助类型
首先保留你的HasID接口,然后我们需要一个辅助类型来提取对象中属性类型符合HasID的键:
interface HasID { id: number; } // 辅助类型:筛选出对象O中属性类型继承HasID的所有键 type KeysWithID<O> = { [K in keyof O]: O[K] extends HasID ? K : never }[keyof O];
这个辅助类型的逻辑是:遍历对象O的每个键K,如果对应的属性O[K]是HasID的子类型,就保留键K,否则标记为never;最后通过[keyof O]把所有有效的键提取出来,形成一个联合类型。
第二步:实现泛型get函数
接下来用这个辅助类型约束函数的泛型参数,这样就能自动校验传入的键是否合法:
function get<O extends object, K extends KeysWithID<O>>(obj: O, key: K): O[K] { return obj[key]; }
这里的泛型参数O是输入对象的类型,K被约束为KeysWithID<O>——也就是说,只有那些对应属性符合HasID的键才能被传入。返回类型直接用O[K],因为TypeScript已经知道这个属性必然是HasID的子类型,不需要额外的T参数。
测试用例验证
现在来测试你的示例场景,完全符合预期:
let obj = { foo: 123, bar: { id: 123 }, baz: { id: 'abc' } }; get(obj, 'foo'); // ❌ 类型错误:"foo"对应的属性是数字,不符合HasID get(obj, 'bar'); // ✅ 正常运行,返回类型是{ id: number; } get(obj, 'baz'); // ❌ 类型错误:baz的id是字符串,不符合HasID的number类型要求
解释你原来的问题
你之前的HasPropertyWithID接口定义有问题:类型参数K不能直接作为属性名使用(应该用映射类型或索引签名),而且泛型参数的顺序和约束逻辑没有建立起O[K]和T的明确关联,导致TypeScript无法确认obj[key]的类型就是T,所以抛出了赋值错误。
内容的提问来源于stack exchange,提问作者Mr Alpha
相关产品推荐
相关产品推荐

