TypeScript中使用createAsyncThunk:设置fulfilledAction的meta类型及解决TS报错
问题描述
按照Redux Toolkit文档,尝试通过fulfillWithValue(value, meta)的第二个参数返回currentPage等元数据,但TypeScript提示只能传入一个参数。
代码示例:
const findBooks = createAsyncThunk( "books/findBooks", async (filterQuery: string, thunkAPI) => { const { books, page } = await fetchBooks(filterQuery); // 报错:Expected 1 argument, but got 2. ts(2554) return thunkAPI.fulfillWithValue(books, { page }); } );
对应的slice代码:
const usersSlice = createSlice({ name: "mySlice", initialState: {}, reducers: {}, extraReducers: (builder) => { builder .addCase(findBooks.pending, (state, action) => {}) .addCase(findBooks.fulfilled, (state, action) => { state.search.currentPage = action.meta.page; }) .addCase(findBooks.rejected, (state, action) => {}); }, });
曾尝试扩展ThunkAPI类型,但认为不是最优方案:
interface MetaThunkAPI extends BaseThunkAPI<any, any> { fulfillWithValue: <T = any, S = any>(value: T, meta: S) => T; }
解决方法
方法1:给createAsyncThunk显式指定泛型参数
Redux Toolkit的createAsyncThunk支持泛型定义,格式为createAsyncThunk<Returned, ThunkArg, ThunkApiConfig>,其中ThunkApiConfig可指定meta的类型。通过显式声明泛型参数,能让TypeScript正确识别fulfillWithValue的第二个参数:
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'; // 定义返回的数据类型和meta类型 interface BooksResponse { // 定义你的书籍数据结构 } interface FindBooksMeta { page: number; } const findBooks = createAsyncThunk< BooksResponse, // 异步操作返回的数据类型 string, // 传入thunk的参数类型 { meta: FindBooksMeta; // 指定自定义meta的类型 } >( "books/findBooks", async (filterQuery: string, thunkAPI) => { const { books, page } = await fetchBooks(filterQuery); // 此时TypeScript不再报错,且能识别第二个参数为meta return thunkAPI.fulfillWithValue(books, { page }); } );
之后在slice的fulfilled回调中,action.meta会自动拥有page属性的类型提示:
const booksSlice = createSlice({ name: "books", initialState: { search: { currentPage: 1, books: [] as BooksResponse[] } }, reducers: {}, extraReducers: (builder) => { builder .addCase(findBooks.fulfilled, (state, action) => { state.search.currentPage = action.meta.page; // 类型合法,无报错 state.search.books = action.payload; }); }, });
方法2:直接返回包含数据和meta的对象(不使用fulfillWithValue)
如果不想配置泛型,也可以直接把数据和meta打包成一个对象返回,后续在slice中拆分处理:
const findBooks = createAsyncThunk( "books/findBooks", async (filterQuery: string) => { const { books, page } = await fetchBooks(filterQuery); return { books, page }; // 直接返回包含所有信息的对象 } ); // 在slice中处理 const booksSlice = createSlice({ name: "books", initialState: { search: { currentPage: 1, books: [] as BooksResponse[] } }, reducers: {}, extraReducers: (builder) => { builder .addCase(findBooks.fulfilled, (state, action) => { state.search.currentPage = action.payload.page; state.search.books = action.payload.books; }); }, });
不推荐扩展ThunkAPI类型的原因
你尝试扩展BaseThunkAPI的方式会绕过Redux Toolkit的内置类型约束,可能导致后续action.meta无法自动识别自定义类型,出现类型不匹配的问题。而通过createAsyncThunk的泛型参数配置是官方推荐的类型安全方案。
内容的提问来源于stack exchange,提问作者Alexandre
相关产品推荐
相关产品推荐

