TypeScript中使用in操作符时如何避免代码重复?
解决TypeScript联合类型中重复检查属性的问题
你遇到的问题本质是TypeScript的类型缩小机制需要明确的属性存在性检查——虽然逻辑上真值判断隐含了属性存在,但TS的类型系统不会自动推导这一点。下面给你两种可行的解决方案:
方案一:针对特定类型写自定义类型守卫
既然你明确要判断obj是否为A类型,直接写一个专门的类型守卫函数最直观,完全避免重复写属性名:
type A = { foo: string bar: string } type B = { baz: string } type U = A | B; // 专门判断是否为A类型的守卫 function isA(obj: U): obj is A { return 'foo' in obj && !!obj.foo; } function f(obj: U) { if (isA(obj)) { console.log(obj.foo, obj.bar); // TS能正确推断obj是A类型 } }
这种方式的好处是类型推断最精准,代码可读性也高,适合固定的联合类型场景。
方案二:通用的真值属性检查工具函数
如果需要一个通用的工具函数处理各种类型,可以通过泛型约束修复你之前的类型谓词错误,同时让TS能推断更精确的类型:
function hasTruthyProp<T, K extends PropertyKey>(obj: T, prop: K): obj is T & Record<K, NonNullable<T[K]>> { return prop in obj && !!obj[prop as keyof T]; } // 回到你的例子中使用: function f(obj: U) { if (hasTruthyProp(obj, 'foo')) { console.log(obj.foo, obj.bar); // TS会自动排除B类型,推断obj为A } }
这个函数通过泛型K约束属性名的类型,返回类型中把该属性标记为非空值。因为B类型没有foo属性,TS会自动在if块里把obj缩小为A类型,自然能访问bar。
需要注意的是,通用函数在复杂联合类型下可能需要更精细的类型处理,但针对你的场景完全够用。
内容的提问来源于stack exchange,提问作者waxwing
相关产品推荐
相关产品推荐

