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

RTK Query同端点不同响应的TypeScript类型定义问题

解决RTK Query中动态响应类型的TypeScript类型匹配问题

问题描述

我是TypeScript新手,在RTK Query中定义了一个查询端点,该端点会根据传入的filter参数返回不同结构的响应数组。但在组件中使用useGetIndicesQuery钩子时,TypeScript会因字段不存在的类型不匹配报错。相关代码如下:

export type RecentScore = { ndays: number | ''; score: number | '' };

export type TradeScore = {
    startValue: number | '';
    score: number | '';
};

export interface IGetIndices {
    id: number;
    name: string;
    issuerAccountId: number;
    isDefault: boolean;
    startDate: Date;
    createdAt: Date;
    updatedAt: Date;
}

export interface IGetTradeVolume extends IGetIndices {
    scores: { M: TradeScore[] };
}

export interface IGetRecent extends IGetIndices {
    scores: { R: RecentScore[] };
}

getIndices: builder.query<
            IGetTradeVolume[] | IGetRecent[],
            { page: number; size: number; filter: string }
        >({
            query: ({ page, size, filter }) => ({
                url: `/club/indices?${ParamsHandler({ page, size, filter })}`,
                method: 'GET'
            }),
            providesTags: (result) => {
                return result
                    ? [...result.map(({ id }) => ({ type: 'Club' as const, id })), 'Club']
                    : ['Club'];
            }
        })

解决方案

方案一:优化单个端点的类型定义(无需拆分)

核心是让TypeScript根据filter的具体值自动推断响应类型,通过条件类型关联参数与返回值:

  1. 定义filter与响应类型的映射关系
// 明确每个filter对应的响应类型
type FilterResponseMap = {
  'trade-volume': IGetTradeVolume[];
  'recent': IGetRecent[];
};

// 提取合法的filter值类型
type ValidFilter = keyof FilterResponseMap;
  1. 修改查询端点的类型声明
    通过泛型和条件类型实现参数与返回值的关联:
getIndices: <T extends ValidFilter>() => builder.query<
  FilterResponseMap[T],
  { page: number; size: number; filter: T }
>({
  query: ({ page, size, filter }) => ({
    url: `/club/indices?${ParamsHandler({ page, size, filter })}`,
    method: 'GET'
  }),
  providesTags: (result) => {
    return result
      ? [...result.map(({ id }) => ({ type: 'Club' as const, id })), 'Club']
      : ['Club'];
  }
})
  1. 组件中使用时的自动类型推断
    传入具体的filter值后,TypeScript会自动匹配对应响应类型:
// data会被推断为IGetTradeVolume[]
const { data } = useGetIndicesQuery({ page: 1, size: 10, filter: 'trade-volume' });
// data会被推断为IGetRecent[]
const { data } = useGetIndicesQuery({ page: 1, size: 10, filter: 'recent' });

方案二:拆分为独立端点(更直观)

如果filter对应的响应逻辑差异大,拆分端点能让代码更清晰,避免复杂类型逻辑:

  1. 拆分后的端点定义
// 交易成交量数据查询
getTradeVolumeIndices: builder.query<IGetTradeVolume[], { page: number; size: number }>({
  query: ({ page, size }) => ({
    url: `/club/indices?${ParamsHandler({ page, size, filter: 'trade-volume' })}`,
    method: 'GET'
  }),
  providesTags: (result) => {
    return result
      ? [...result.map(({ id }) => ({ type: 'Club' as const, id })), 'Club']
      : ['Club'];
  }
}),

// 近期数据查询
getRecentIndices: builder.query<IGetRecent[], { page: number; size: number }>({
  query: ({ page, size }) => ({
    url: `/club/indices?${ParamsHandler({ page, size, filter: 'recent' })}`,
    method: 'GET'
  }),
  providesTags: (result) => {
    return result
      ? [...result.map(({ id }) => ({ type: 'Club' as const, id })), 'Club']
      : ['Club'];
  }
})
  1. 组件中直接调用对应钩子
const { data: tradeVolumeData } = useGetTradeVolumeIndicesQuery({ page: 1, size: 10 });
const { data: recentData } = useGetRecentIndicesQuery({ page: 1, size: 10 });

方案选择建议

  • 若filter对应的响应结构差异小、需灵活切换,优先用方案一,减少代码冗余;
  • 若响应结构差异大或后续会扩展更多filter类型,优先用方案二,代码可读性和可维护性更高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 11:45:55