You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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理解这个布尔值背后的类型含义。

解决方案步骤:

  1. 定义针对当前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)
}
  1. 修改原函数中的判断逻辑
    用这个类型守卫函数替换原来的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 18:40:58