如何访问仅存在于联合返回类型之一的属性?
TypeScript联合类型访问属性报错的解决方法
问题场景
调用函数返回联合类型:
const accountDetails: IAccount | ISmallError = getAccount()
尝试直接访问属性时触发编译错误:
if (accountDetails.error) return response.json({ error: error.error });
错误提示:
Property 'error' does not exist on type 'IAccount | ISmallError'. Property 'error' does not exist on type 'IAccount'.ts(2339)
你当前的解决方案是使用类型断言:
const err = accountDetails as ISmallError; if (err.error) return response.json({ accountDetails: "No account found" });
方案评价与优化
你现在用的类型断言不是最优方案,因为它跳过了TypeScript的类型检查:如果accountDetails实际是IAccount类型,断言后访问err.error会得到undefined,存在运行时风险。
推荐以下更安全、符合TypeScript设计理念的解决方式:
1. 使用in操作符做类型守卫
这是最简单的方式,通过检查属性是否存在来缩小类型范围:
if ('error' in accountDetails) { // 此处TypeScript会自动推断accountDetails为ISmallError类型 return response.json({ error: accountDetails.error }); } // 下方代码中,accountDetails会被自动推断为IAccount类型,可安全访问其属性
2. 自定义类型守卫函数
如果需要更复杂的类型判断逻辑,可以封装守卫函数:
function isSmallError(obj: IAccount | ISmallError): obj is ISmallError { return (obj as ISmallError).error !== undefined; } if (isSmallError(accountDetails)) { return response.json({ error: accountDetails.error }); } // 后续代码自动推断accountDetails为IAccount类型
3. 定义区分式联合类型(Discriminated Union)
如果可以修改类型定义,给两个类型添加共同的区分字段,能让类型判断更清晰:
// 修改类型定义 interface IAccount { type: 'account'; // IAccount原有属性... } interface ISmallError { type: 'error'; error: string; // ISmallError原有属性... } // 判断逻辑 if (accountDetails.type === 'error') { return response.json({ error: accountDetails.error }); } // 下方自动推断为IAccount类型
这些方案既能通过编译检查,又能保证运行时的类型安全,比直接断言更可靠。
内容的提问来源于stack exchange,提问作者plutownium
相关产品推荐
相关产品推荐

