TypeScript 4.8升级后Axios响应出现unknown类型报错求助
Object is of type 'unknown'错误 问题背景
将Ionic React + TypeScript应用升级到TypeScript 4.8.2后,原有的Axios错误处理代码出现Object is of type 'unknown'编译错误,使用的Axios版本为0.27.2,该代码在TypeScript 4.7中可正常构建。
问题代码:
const handleErrorsPostAuth = (error: AxiosError) => { if (error?.response) { // 提示Object is of type 'unknown' if (error.response.data.errors[0]) { // 提示Object is of type 'unknown' throw new Error(error.response.data.errors[0].detail); } throw new Error(error.response.toString()); } throw new Error(error.message); };
原因分析
TypeScript 4.8对类型检查的严格性有所提升,而Axios的AxiosError接口默认泛型参数为unknown:
interface AxiosError<T = unknown, D = any> extends Error { // ... 其他属性 response?: AxiosResponse<T, D>; }
这意味着error.response.data的类型默认是unknown,而TypeScript 4.7中可能因类型推断或检查宽松度问题,默认将其视为any,因此没有报错。
另外,你尝试用instanceof AxiosResponse的方式无效,是因为AxiosResponse是TypeScript接口(仅编译时存在),而非JavaScript类,instanceof只能检查运行时存在的类实例,所以无法通过这种方式收窄类型。
解决方案
方案1:为AxiosError指定响应数据泛型
最规范的方式是提前定义错误响应数据的类型,并为AxiosError指定泛型参数:
// 定义错误响应数据的结构 interface ApiErrorResponse { errors: Array<{ detail: string; }>; } const handleErrorsPostAuth = (error: AxiosError<ApiErrorResponse>) => { if (error?.response) { if (error.response.data.errors[0]) { throw new Error(error.response.data.errors[0].detail); } throw new Error(error.response.toString()); } throw new Error(error.message); };
这种方式直接明确了data的类型,无需额外类型收窄,是类型安全的最优解。
方案2:使用类型守卫收窄类型
如果无法提前指定泛型(比如响应结构不固定),可以编写自定义类型守卫函数,在运行时检查数据结构,同时让TypeScript识别类型:
// 自定义类型守卫,检查是否符合错误响应结构 function isApiErrorResponse(data: unknown): data is { errors: Array<{ detail: string }> } { return ( typeof data === 'object' && data !== null && 'errors' in data && Array.isArray((data as any).errors) && (data as any).errors.length > 0 && typeof (data as any).errors[0].detail === 'string' ); } const handleErrorsPostAuth = (error: AxiosError) => { if (error?.response) { const responseData = error.response.data; if (isApiErrorResponse(responseData)) { throw new Error(responseData.errors[0].detail); } throw new Error(error.response.toString()); } throw new Error(error.message); };
类型守卫函数会在运行时验证数据结构,同时告诉TypeScript符合条件的data属于指定类型,实现类型安全的收窄。
方案3:临时使用类型断言(不推荐)
如果需要快速临时解决问题,可以使用类型断言跳过TypeScript的类型检查,但这种方式会丢失类型安全性,仅建议作为过渡方案:
const handleErrorsPostAuth = (error: AxiosError) => { if (error?.response) { const errorData = error.response.data as { errors: Array<{ detail: string }> }; if (errorData.errors[0]) { throw new Error(errorData.errors[0].detail); } throw new Error(error.response.toString()); } throw new Error(error.message); };
内容的提问来源于stack exchange,提问作者Patrick Kenny

