React Query自定义请求类型校验报错:error为unknown的解决方法
解决React Query中error类型为unknown的TypeScript报错
你在使用TypeScript + React Query编写自定义请求函数时,访问locationQuery.error.message遇到TypeScript错误,提示'locationQuery.error' is of type 'unknown',对应的类型是QueryObserverRefetchErrorResult<IResponse, unknown> | QueryObserverLoadingErrorResult<IResponse, unknown>。
你的核心代码如下:
interface IResponse extends IGeolocation { /* ... 接口定义 */ } export async function getLocation(searchTerm: string): Promise<IResponse> { const result = await geopuntApi.get(`/geolocation/location?q=${searchTerm}`); return result.data.LocationResult; } export function useLocation(searchTerm: string) { return useQuery<IResponse>( ['location', { searchTerm }], () => getLocation(searchTerm), { enabled: !!searchTerm }, ); }
使用时的错误代码:
const locationQuery = useLocation(searchTerm); {locationQuery.isError && <p>{locationQuery.error.message}</p>} // 此处报错
问题原因
React Query默认将错误类型设为unknown,因为它无法提前知晓你的请求会抛出何种类型的错误,这是TypeScript严格类型检查导致的报错。
解决方案
方案1:显式指定错误类型给useQuery
在useQuery的泛型参数中,第二个参数明确指定错误类型(比如通用的Error类型),这样React Query会将error的类型推断为你指定的类型:
export function useLocation(searchTerm: string) { console.log(`searchTerm binnen useLocation: ${searchTerm}`); // 泛型添加Error类型作为第二个参数 return useQuery<IResponse, Error>( ['location', { searchTerm }], () => getLocation(searchTerm), { enabled: !!searchTerm, }, ); }
修改后,locationQuery.error会被TypeScript识别为Error类型,直接访问.message就不会报错。
方案2:自定义错误类型并使用类型守卫(更安全)
如果你的API返回自定义格式的错误(比如包含message、statusCode等字段),可以先定义错误接口,再通过类型守卫缩小类型范围,确保类型安全:
- 定义自定义错误接口:
// 根据你的API实际返回的错误格式调整 interface ApiError { message: string; statusCode: number; }
- 编写类型守卫函数:
function isApiError(error: unknown): error is ApiError { return ( typeof error === 'object' && error !== null && 'message' in error && typeof (error as ApiError).message === 'string' ); }
- 使用时判断类型:
{locationQuery.isError && ( <p>{isApiError(locationQuery.error) ? locationQuery.error.message : '请求失败,请稍后重试'}</p> )}
这种方式避免了强制类型断言的不安全问题,同时能处理不同类型的错误情况。
方案3:临时强制类型断言(不推荐)
如果只是临时快速解决,也可以用类型断言直接指定错误类型,但这种方式跳过了TypeScript的类型检查,存在风险:
{locationQuery.isError && <p>{(locationQuery.error as Error).message}</p>}
内容的提问来源于stack exchange,提问作者intercoder
相关产品推荐
相关产品推荐

