You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 11:30:17