如何收窄类型解决TS2339:类型'Error|TypeWithData'不存在属性'data'?
问题根因
你的getCsrfToken函数当前的返回值类型为 Promise<CSRFToken | Error>,可选链操作符?.仅能识别并收窄undefined/null类型,无法区分联合类型中都不为空的CSRFToken和Error类型,所以你在调用函数后直接读取.data属性时,TS无法确认当前值不是Error实例,就会抛出该警告。
另外你当前的写法还有一个逻辑漏洞:axios本身在请求返回4xx/5xx状态码时会直接抛出异常,你没有捕获这部分异常,现在写的返回Error的逻辑仅能覆盖「请求成功但响应无data」的场景,请求失败的场景会直接走Promise.reject,不会触发你写的返回逻辑。
推荐解决方案(符合async函数常规设计)
直接把返回Error改为抛出错误,这样函数返回值类型会变成Promise<CSRFToken>,不存在联合类型的问题,上层调用时统一用try/catch处理所有错误场景即可:
const getCsrfToken = async () => { const csrfTokenResponse = await axios.get<any, AxiosResponse<CSRFToken>>(csrfUrl); if (csrfTokenResponse?.data) { return csrfTokenResponse.data; } throw new Error('Failed to fetch CSRF token.'); };
调用示例:
try { const csrfToken = await getCsrfToken(); // 直接使用csrfToken,类型已经是CSRFToken console.log(csrfToken.data); } catch (e) { // 处理所有错误逻辑,包括请求失败、无data两种场景 console.error((e as Error).message); }
可选方案(坚持返回Error的场景)
如果你确实不想用throw抛错,需要上层通过返回值判断是否出错,就需要在读取属性前先通过instanceof做类型收窄:
const tokenOrError = await getCsrfToken(); if (tokenOrError instanceof Error) { // 处理错误 console.error(tokenOrError.message); } else { // 此处TS自动收窄类型为CSRFToken,读取data不会报错 console.log(tokenOrError.data); }
内容的提问来源于stack exchange,提问作者Patrick Kenny
相关产品推荐
相关产品推荐

