TypeScript中Object.hasOwn与hasOwnProperty无法按预期收窄类型
解决TypeScript中hasOwnProperty/hasOwn无法收窄键类型的问题
问题分析
Object.entries()返回的键类型是string,而TypeScript默认的hasOwnProperty()和Object.hasOwn()的类型定义并没有将string收窄为目标对象的具体键类型(比如示例中的ExampleKeys),这是因为这些方法的类型签名未关联到具体对象的键集合。
通用解决方案:自定义类型守卫
可以编写一个自定义类型守卫函数,专门判断键是否属于目标对象的键类型,让TypeScript正确收窄类型:
type Example = { foo: string; bar: string; } type ExampleKeys = keyof Example; const translation: Readonly<{[key in ExampleKeys]: string}> = { foo: "oof", bar: "rab", }; // 自定义类型守卫函数 function isKeyOf<T extends object>(obj: T, key: PropertyKey): key is keyof T { return Object.hasOwn(obj, key); } function test(example: Example) { for (const [key, _] of Object.entries(example)) { if (isKeyOf(translation, key)) { // 此处key的类型已被收窄为ExampleKeys console.log(translation[key]); // 类型安全,无报错 } } }
原理说明
自定义类型守卫通过key is keyof T的返回类型断言,告知TypeScript:当函数返回true时,传入的key必然是T类型对象的键类型。这样在if分支内部,TypeScript能准确识别key的具体类型,既避免了类型断言,又保证了类型安全。
额外优化:直接遍历已知键集合
如果无需处理example的额外属性,也可以直接遍历目标键集合,从根源规避类型问题:
function test(example: Example) { // 直接遍历已知的键类型集合 (Object.keys(translation) as ExampleKeys[]).forEach(key => { if (Object.hasOwn(example, key)) { console.log(example[key], translation[key]); } }); }
这种方式更直接,适合只需要处理目标键的场景。
内容的提问来源于stack exchange,提问作者yotamN
相关产品推荐
相关产品推荐

