React Query组合函数:如何编写TypeScript类型守卫解决isSuccess推断问题
解决TypeScript中isSuccess状态无法推断data存在的问题
先看你的原始代码:
import { UseQueryResult } from "@tanstack/react-query" export function combine( results: [ UseQueryResult<{ user: { id: string } }>, UseQueryResult<{ companies: [{ id: string }] }>, ], ) { const isSuccess = results.every(result => result.isSuccess) function getValue() { // 想用 if (isSuccess) { 替换当前判断,但TS无法识别data存在 if (results[0].isSuccess && results[1].isSuccess) { const [ { data: { user }, }, { data: { companies }, }, ] = results return { companies, user } } return void 0 } return { isSuccess, value: getValue(), } }
问题核心:results.every(result => result.isSuccess)返回的只是普通boolean,TypeScript无法关联这个布尔值和数组中每个元素的isSuccess状态、data的存在性。你需要用类型谓词函数(自定义类型守卫)来让TS理解这个布尔值背后的类型含义。
解决方案步骤:
- 定义针对当前results数组的类型守卫函数
这个函数返回类型谓词,明确当返回true时,数组的每个元素都处于成功状态,且data不为undefined:
function areAllQueriesSuccess( results: [UseQueryResult<{ user: { id: string } }>, UseQueryResult<{ companies: [{ id: string }] }>] ): results is [ UseQueryResult<{ user: { id: string } }> & { isSuccess: true; data: { user: { id: string } } }, UseQueryResult<{ companies: [{ id: string }] }> & { isSuccess: true; data: { companies: [{ id: string }] } } ] { return results.every(result => result.isSuccess) }
- 修改原函数中的判断逻辑
用这个类型守卫函数替换原来的every调用,即可让TypeScript正确推断类型:
修改后的完整代码:
import { UseQueryResult } from "@tanstack/react-query" function areAllQueriesSuccess( results: [UseQueryResult<{ user: { id: string } }>, UseQueryResult<{ companies: [{ id: string }] }>] ): results is [ UseQueryResult<{ user: { id: string } }> & { isSuccess: true; data: { user: { id: string } } }, UseQueryResult<{ companies: [{ id: string }] }> & { isSuccess: true; data: { companies: [{ id: string }] } } ] { return results.every(result => result.isSuccess) } export function combine( results: [ UseQueryResult<{ user: { id: string } }>, UseQueryResult<{ companies: [{ id: string }] }>, ], ) { const isSuccess = areAllQueriesSuccess(results) function getValue() { if (isSuccess) { const [ { data: { user } }, { data: { companies } }, ] = results return { companies, user } } return void 0 } return { isSuccess, value: getValue(), } }
原理说明:
类型谓词results is [...]告诉TypeScript:当areAllQueriesSuccess返回true时,传入的results数组的每个元素都符合isSuccess: true且data明确存在的类型,此时解构data就不会出现undefined的类型报错。
如果想让类型守卫适配更多场景,可以用泛型简化:
type SuccessQueryResult<T> = UseQueryResult<T> & { isSuccess: true; data: T } function areAllQueriesSuccess<T extends readonly UseQueryResult<any>[]>( results: T ): results is { [K in keyof T]: SuccessQueryResult<Awaited<T[K]['data']>> } { return results.every(result => result.isSuccess) }
这个泛型版本会自动推导每个查询结果的成功类型,无需手动重复定义数组元素类型。
内容的提问来源于stack exchange,提问作者Pavel Perevezencev
相关产品推荐
相关产品推荐

