RTK Query中updateCachedData的draft参数push方法报错问题
问题根因
draft.push报类型错误+运行时错误,核心原因是RTK Query无法推断当前endpoint缓存值的类型,且实际缓存的根数据并不是你以为的数组类型,通常由以下几种错误写法触发:
- 定义
builder.query时未传入正确的泛型参数,TS无法推导缓存数据结构,将draft识别为void/any - 接口返回值是带外层包装的对象(如
{code:0, data: []}),未配置transformResponse拆解出目标数组,导致缓存里存的是整个对象而非数组,自然不存在push方法 - 误将
onCacheEntryAdded配置在了mutation类型的endpoint上,mutation无长期持久化的缓存条目,updateCachedData无法拿到有效的可修改草稿 - 缓存根数据是对象(如分页结构
{list: [], total: number}),直接在根draft上调用push,没有定位到实际的数组字段
修复方案
1. 给query endpoint显式声明类型,配置正确的响应转换
以消息列表实时更新场景为例,正确的endpoint写法如下:
// 先定义单条消息的类型 type ChatMessage = { id: string content: string userId: string createTime: number } export const apiSlice = createApi({ reducerPath: 'api', baseQuery: fetchBaseQuery({ baseUrl: 'http://localhost:5994' }), endpoints: (builder) => ({ // 重点:builder.query传入两个泛型参数,第一个为缓存最终存储的类型,第二个为查询入参类型 getMessageList: builder.query<ChatMessage[], void>({ query: () => '/api/messages', // 如果接口返回带外层包装,必须通过transformResponse拆解出目标数组,和泛型声明的类型对齐 transformResponse: (rawRes: { code: number; data: ChatMessage[] }) => rawRes.data, async onCacheEntryAdded(arg, { updateCachedData, cacheDataLoaded, cacheEntryRemoved }) { const ws = new WebSocket("ws://localhost:5994/ws"); try { // 等待初始查询完成,缓存条目存在后再绑定消息监听 await cacheDataLoaded; const listener = (event: MessageEvent) => { const newMessage = JSON.parse(event.data) as ChatMessage; updateCachedData((draft) => { // 此处TS会自动推断draft为ChatMessage[]类型,无类型错误 draft.push(newMessage); }); }; ws.addEventListener("message", listener); } catch { // 可在此补充ws连接失败的重连逻辑 } // 缓存条目移除时主动关闭ws连接,避免内存泄漏 await cacheEntryRemoved; ws.close(); }, }) }) })
2. 针对性排查
- 若使用分页结构,缓存类型声明为
{list: ChatMessage[], total: number}时,更新逻辑要改为draft.list.push(newMessage) - 不要在mutation上使用
onCacheEntryAdded做缓存更新,mutation的缓存不会被持久化,生命周期触发逻辑不符合预期 - 不要用
as any强行绕过类型检查,优先对齐泛型声明、transformResponse返回值、实际更新逻辑三者的数据结构
同类写法正常运行的原因
其他开发者的代码中,要么显式传入了query的泛型参数,要么TS可以从query返回值、transformResponse返回值自动推导出缓存值的正确类型,运行时缓存的根数据确实是数组实例,因此不会触发类型和运行时错误。
内容的提问来源于stack exchange,提问作者JC1
相关产品推荐
相关产品推荐

