React Query+TS扩展useQuery强制queryKey为至少2项数组的方法
扩展useQuery实现queryKey强制校验方案
1. 扩展原生useQuery的实现方式
不需要重写react-query的核心逻辑,只需要写一层薄包装函数:
- 内部直接透传所有参数给原生
useQuery,完全复用原有所有功能(缓存、状态管理、配置项等都不受影响) - 可选在开发环境增加运行时校验,避免TS被
any等类型绕过的非法传参 - 保留原生
useQuery的全部泛型推导能力,不会丢失data、error等字段的类型提示
2. TypeScript类型规则定义
核心是用TS可变元组类型约束queryKey必须为至少包含2个元素的数组,基础类型定义为:
// 约束目标:最少2个元素的数组 type ValidQueryKey = [unknown, unknown, ...unknown[]];
这个类型会自动过滤两种非法传参:
- 非数组类型(比如单独传字符串作为queryKey)
- 数组长度小于2的情况
完整实现代码
// 导入原生useQuery,注意v4+版本包名为@tanstack/react-query,v3及更早为react-query import { useQuery as baseUseQuery } from '@tanstack/react-query'; import type { UseQueryOptions, UseQueryResult } from '@tanstack/react-query'; // 定义合法queryKey类型:长度至少为2的数组 type ValidQueryKey = [unknown, unknown, ...unknown[]]; // 重载1:支持(queryKey, options)传参格式 export function useQuery< TQueryFnData = unknown, TError = unknown, TData = TQueryFnData, TQueryKey extends ValidQueryKey = ValidQueryKey >( queryKey: TQueryKey, options?: Omit<UseQueryOptions<TQueryFnData, TError, TData, TQueryKey>, 'queryKey'> ): UseQueryResult<TData, TError>; // 重载2:支持(queryKey, queryFn, options)传参格式 export function useQuery< TQueryFnData = unknown, TError = unknown, TData = TQueryFnData, TQueryKey extends ValidQueryKey = ValidQueryKey >( queryKey: TQueryKey, queryFn: UseQueryOptions<TQueryFnData, TError, TData, TQueryKey>['queryFn'], options?: Omit<UseQueryOptions<TQueryFnData, TError, TData, TQueryKey>, 'queryKey' | 'queryFn'> ): UseQueryResult<TData, TError>; // 实现层 export function useQuery( queryKey: ValidQueryKey, arg2?: any, arg3?: any ) { // 开发环境运行时校验,不需要可直接删除 if (process.env.NODE_ENV !== 'production') { if (!Array.isArray(queryKey)) { throw new Error('queryKey必须是数组类型'); } if (queryKey.length < 2) { throw new Error('queryKey数组至少需要包含2个元素'); } } // 透传参数给原生useQuery return baseUseQuery(queryKey, arg2, arg3); }
校验效果验证
对应给出的用例:
const { data } = useQuery<Data, Error>(["module_1", "fetchA"], fetchFn); // ✅ 校验通过 const { data } = useQuery<Data, Error>("module_1", fetchFn); // ❌ TS报错:类型string不符合ValidQueryKey约束 const { data } = useQuery<Data, Error>(["module_1"], fetchFn); // ❌ TS报错:元组长度为1,不足2位
注意:该实现依赖TS 4.0及以上版本支持的可变元组特性,目前绝大多数前端项目的TS版本都满足该要求。
内容的提问来源于stack exchange,提问作者Zuy BK
相关产品推荐
相关产品推荐

