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

React Query自定义查询构建器的TypeScript类型报错问题求助

解决React Query查询构建器中TypeScript类型推断失效问题

我明白你遇到的问题了——当给查询构建器的方法加上...config扩展后,TypeScript就无法正确推断useQuery返回的data类型了,这确实是React Query结合TypeScript时常见的类型陷阱之一。

问题根源

你当前使用的QueryObserverOptions是一个泛型类型,如果不指定泛型参数,它默认的data类型是unknown。当你展开...config时,TypeScript会认为这个config可能包含覆盖queryFn或者改变返回数据类型的配置,于是就把最终合并后的查询配置的data类型降级为unknown,导致后续访问events.data.locationEvents时报错。

而当你移除...config时,查询配置的queryFn明确返回Promise<LocationEvents>,React Query的useQuery能直接从queryFn的返回值推断出data的类型,所以一切正常。

解决方案

我们需要给QueryObserverOptions指定明确的泛型参数,让TypeScript知道查询的原始数据类型是LocationEvents,同时保留用户通过config(比如select选项)自定义返回数据类型的灵活性。

1. 给查询方法添加泛型支持

修改你的locationsQueries,让每个查询方法支持泛型,允许用户自定义最终返回的data类型(默认是LocationEvents):

import { QueryObserverOptions } from '@tanstack/react-query'
import { get } from '../request/request'

type LocationEvents = { locationEvents: Array<LocationEvent> }

export const locationsQueries = {
  events: {
    // 泛型T允许用户通过select自定义返回类型,默认是LocationEvents
    all: <T = LocationEvents>(
      config: QueryObserverOptions<LocationEvents, unknown, T> = {}
    ) => ({
      queryKey: [{ scope: 'locations', type: 'all' }] as const,
      queryFn: () => get('/locations/events').resolve<LocationEvents>(),
      ...config,
    }),
    byLocation: <T = LocationEvents>(
      locationId: string,
      config: QueryObserverOptions<LocationEvents, unknown, T> = {}
    ) => ({
      queryKey: [
        { scope: 'locations', type: 'byLocation', locationId },
      ] as const,
      queryFn: () => get(`/locations/${locationId}/events`).resolve<LocationEvents>(),
      ...config,
    }),
  },
}

2. 验证效果

现在不管你是否传入config,TypeScript都能正确推断类型:

  • 不传入config时:
    const events = useQuery(locationsQueries.events.all())
    // events.data 会被推断为 LocationEvents,访问locationEvents完全正常
    
  • 传入带select的config时:
    const events = useQuery(locationsQueries.events.all({
      select: (data) => data.locationEvents
    }))
    // events.data 会被自动推断为 Array<LocationEvent>
    

额外说明

  • QueryObserverOptions的泛型参数顺序是:QueryObserverOptions<QueryFnData, Error, Data, QueryKey>,我们这里指定了QueryFnData为LocationEvents(queryFn返回的原始数据类型),Data为泛型T(最终返回给组件的数据类型)。
  • 确保你的RequestBuilder.resolve方法的泛型是正确的,当前的async resolve<T extends unknown>(): Promise<T>写法没问题,但可以简化为async resolve<T>(): Promise<T>,效果是一样的。

内容的提问来源于stack exchange,提问作者Mugetsu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 16:18:16