如何在RTK Query中编写类型正确的查询Hook包装函数
RTK Query 包装Hook类型报错修复
问题根因
data属性不存在的TS报错:自定义的selectFromResult类型定义打断了RTK Query原生的类型推导链,当传入自定义select配置时,TS会将hook返回值收窄为select函数的返回结构,当前泛型定义没有和原生hook的返回类型做关联,导致TS误判返回值仅包含refetch属性,无法识别data字段。- 类型无法收窄的问题:没有通过函数重载区分
arg2是否传入的两种入参场景,TS无法根据入参形态推导对应的data类型,只能返回t1 | t1[]联合类型。
修复代码
// 保留原有自定义结果类型,补充refetch字段兼容原生返回 export type RTKQueryResult<T> = { data?: T; isLoading: boolean; isFetching: boolean; isSuccess: boolean; isError: boolean; refetch: () => void; }; // 函数重载1:未传入arg2时,返回单条t1类型数据 export function useGetTQueryWrapper<RT = RTKQueryResult<t1>>( args: { arg1: string; arg2?: undefined }, options?: { skip?: boolean; selectFromResult?: (result: RTKQueryResult<t1>) => RT; } ): RT; // 函数重载2:传入arg2时,返回t1[]数组类型数据 export function useGetTQueryWrapper<RT = RTKQueryResult<t1[]>>( args: { arg1: string; arg2: string }, options?: { skip?: boolean; selectFromResult?: (result: RTKQueryResult<t1[]>) => RT; } ): RT; // 重载实现逻辑,内部类型不对外暴露 export function useGetTQueryWrapper<RT>( args: { arg1: string; arg2?: string }, options: { skip?: boolean; selectFromResult?: (result: RTKQueryResult<t1 | t1[]>) => RT; } = {} ) { // 透传参数给原生hook,此处类型断言仅用于绕过内部类型校验,对外类型安全由重载保障 const queryResult = useGetTQuery(args, options as any); if (!args.arg2) { return { ...queryResult, data: queryResult.data as t1 } as RT; } return { ...queryResult, data: queryResult.data as t1[] } as RT; }
使用说明
- TS会自动根据传入的
arg2参数匹配对应重载:传入arg2时,selectFromResult的入参result.data类型自动推导为t1[],未传入时自动推导为t1,最终返回的selectedData会自动收窄为对应类型,不会再出现联合类型问题。 - 内部实现中
options as any的写法是安全的,对外暴露的重载签名已经严格约束了入参和返回值的对应关系,不会产生类型漏洞。 - 修复后解构原生hook返回值不会再报
data不存在的错误,类型推导链会通过重载签名正确关联。
内容的提问来源于stack exchange,提问作者LoyalPotato
相关产品推荐
相关产品推荐

