如何处理Typescript联合类型中非共有属性的访问与类型校验问题?
知识点遗漏说明
你遗漏的是 TypeScript 的类型收窄(Narrowing) 相关规则:
- 联合类型变量在完成类型收窄前,仅允许访问所有联合成员共有的属性,
GeneralAPIError和Foo只有status是共有属性,直接访问whatever必然触发类型报错 - 默认情况下 TypeScript 不会将
hasOwnProperty调用的返回值作为类型收窄的依据,因为该方法可被重写,可靠性不足
返回类型最优声明方案
推荐使用 可辨识联合(Discriminated Union) 实现,你现有两个类型都自带 status 字段,刚好可以作为辨识标记,只需要调整成功类型的 status 为字面量类型即可,通用错误类型可以完全复用在所有同类接口函数中:
type GeneralAPIError = { status: "error"; message: string; }; // 仅需把原Foo的status从string改为字面量类型"success" type Foo = { status: "success"; whatever: string; } // 函数返回值类型不需要额外修改 function wat(): Foo | GeneralAPIError { return Math.random() > .5 ? { status: "error", message: "noooo" } : { status: "success", whatever: "yayyy" }; }
使用时直接判断 status 即可自动完成类型收窄,不需要任何类型断言:
const eh = wat(); if (eh.status === "success") { // TS自动将eh收窄为Foo类型,直接访问属性无报错 console.log(eh.whatever); } else { // TS自动将eh收窄为GeneralAPIError类型 console.log(eh.message); }
如果你坚持用「判断属性是否存在」的逻辑
可以自行封装一个通用的类型守卫函数,所有同类场景都可以复用,不需要写断言:
// 通用属性存在判断类型守卫 function hasProperty<T extends object, K extends PropertyKey>(obj: T, key: K): obj is T & Record<K, unknown> { return key in obj; } // 使用示例 const eh = wat(); if (hasProperty(eh, "whatever")) { console.log(eh.whatever); } else { console.log(eh); }
注意:
eh.whatever || eh这种写法无法直接通过类型校验,这是 TypeScript 类型安全的强制要求,你可以改用可选链写法eh?.whatever || eh规避报错,但此时whatever的类型会被推断为string | undefined,仍需额外处理。
内容的提问来源于stack exchange,提问作者BaronVonKaneHoffen
相关产品推荐
相关产品推荐

