如何在reduxjs/toolkit的extraReducer中设置action类型解决类型报错
报错核心原因
- 未给
createAsyncThunk传入正确的泛型参数,导致返回的action.payload类型被推导为unknown catch块直接return error的逻辑错误:createAsyncThunk只有抛出错误/调用rejectWithValue才会触发rejected状态,直接返回错误会被判定为请求成功,同时导致TS推导返回值类型为MovieModel[] | Error,和标注的返回类型冲突- 之前传入泛型时缺少第二个入参类型的声明,导致类型不匹配
修正方案
方案一:使用rejectWithValue返回自定义错误(推荐)
- 修正thunk的类型定义与错误处理逻辑:
import { createAsyncThunk } from '@reduxjs/toolkit'; // 注意替换为你自己的类型定义文件路径 import { MovieModel, MyApiResponse } from './types'; // 泛型参数依次为:成功返回值类型、thunk入参类型、reject返回值类型 export const fetchMoviesAsync = createAsyncThunk< MovieModel[], void, { rejectValue: string } >('movies/fetchMoviesAsync', async (_, { rejectWithValue }) => { try { const response = await fetch( 'https://react-movies-b6b21-default-rtdb.firebaseio.com/movies.json' ); if (!response.ok) { throw new Error('Error fetching data 🐱👤'); } const data = await response.json(); const transformedData: MovieModel[] = Object.entries(data as MyApiResponse).map(([key, value]) => { return { ...value, id: key, }; }); return transformedData; } catch (error) { // 用rejectWithValue返回错误,触发rejected状态 return rejectWithValue((error as Error).message); } });
- 此时slice中的类型会被RTK自动推导,无需额外修改,
action.payload在fulfilled状态下自动为MovieModel[]类型,赋值给state.movies不会再报错。
方案二:直接抛出错误
如果不需要自定义返回错误格式,可以直接抛出错误,无需使用rejectWithValue:
- thunk代码:
export const fetchMoviesAsync = createAsyncThunk<MovieModel[], void>( 'movies/fetchMoviesAsync', async () => { const response = await fetch( 'https://react-movies-b6b21-default-rtdb.firebaseio.com/movies.json' ); if (!response.ok) { throw new Error('Error fetching data 🐱👤'); } const data = await response.json(); const transformedData: MovieModel[] = Object.entries(data as MyApiResponse).map(([key, value]) => { return { ...value, id: key, }; }); return transformedData; });
- 修正slice中rejected逻辑的取值路径:
builder.addCase(fetchMoviesAsync.rejected, (state, action) => { state.isFetching = false; // 直接抛出的错误会存放在action.error对象中 state.errorMessage = action.error.message; });
优化建议
当前slice的name字段取值为movies/fetchMoviesAsync,属于不合理命名,slice的name为全局命名空间,建议修改为name: 'movies',避免后续生成的action type出现前缀重复问题。
内容的提问来源于stack exchange,提问作者Archeon
相关产品推荐
相关产品推荐

