“AsyncThunkAction<any, void, {}>”类型的参数不可分配给“AnyAction”类型的参数

Lun*_*Lun 43 reactjs redux-thunk react-redux redux-toolkit

商店.ts

export const store = configureStore({
    reducer: {
        auth: authReducer
    },
    middleware: [],
});

export type AppDispatch = typeof store.dispatch;
export type RootState = ReturnType<typeof store.getState>;
Run Code Online (Sandbox Code Playgroud)

钩子.ts

export const useAppDispatch = () => useDispatch<AppDispatch>();
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
Run Code Online (Sandbox Code Playgroud)

authSlice.ts(导致问题的函数)

export const fetchUser = createAsyncThunk(
    'users/fetchByTok',
    async () => {
        const res = await getUser();
        return res.data;
    }
)
Run Code Online (Sandbox Code Playgroud)

授权ts

const Auth = ({ component, isLogged }: {component: any, isLogged: boolean}) => {
    const dispatch = useAppDispatch();
    
    useEffect(() => {
        dispatch(fetchUser()) // <----------- ERROR
    }, []);

    return isLogged ? component : <Navigate to='/sign-in' replace={true} />;
}

export default Auth;
Run Code Online (Sandbox Code Playgroud)

我有一个 createAsyncThunk 函数来获取用户,但我实际上无法将其放入dispatch()...

  • “AsyncThunkAction<any, void, {}>”类型的参数不可分配给“AnyAction”类型的参数。
  • 类型“AsyncThunkAction<any, void, {}>”中缺少属性“type”,但类型“AnyAction”中需要属性“type”。ts(2345)

第一次使用这个,所以一个很好的解释会很好:)。

was*_*low 116

我遇到了同样的问题,对我来说,它只是通过添加钩子AppDispatch类型来解决;useDispatch

 const dispatch = useDispatch<AppDispatch>();

 useEffect(() => {
 
   dispatch(getUsers()); 
 }, []);
Run Code Online (Sandbox Code Playgroud)

getUsers() 是我的createAsyncThunk函数

  • 从哪里导入“AppDispatch”? (11认同)
  • @Rafayel https://redux-toolkit.js.org/tutorials/typescript#define-root-state-and-dispatch-types (9认同)
  • 您可以在商店文件中设置 AppDispatch 类型,如文档中所述(此处)(https://redux-toolkit.js.org/usage/usage-with-typescript#getting-the-dispatch-type)。tldr: `导出类型 AppDispatch = typeof store.dispatch` (2认同)

Adi*_*tya 20

其余的答案建议更新store.dispatch推理的类型,我也更喜欢这一点。

在这里,如果由于某种原因您无法通过推理解决问题(这可能发生在较大的项目等中),我想建议使用显式类型定义的替代方案

因此,这里的想法是使用支持 thunk 操作的更新的调度类型显式定义 redux 存储的类型。

使用显式类型声明的解决方案


// your redux store config file.
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
import reducers from "./path/to/reducers";

// ... your code 

// 1. Get the root state's type from reducers
export type RootState = ReturnType<typeof reducers>;

// 2. Create a type for thunk dispatch
export type AppThunkDispatch = ThunkDispatch<RootState, any, AnyAction>;

// 3. Create a type for store using RootState and Thunk enabled dispatch
export type AppStore = Omit<Store<RootState, AnyAction>, "dispatch"> & {
  dispatch: AppThunkDispatch;
};

//4. create the store with your custom AppStore
export const store: AppStore = configureStore();

// you can also create some redux hooks using the above explicit types
export const useAppDispatch = () => useDispatch<AppThunkDispatch>();
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;

Run Code Online (Sandbox Code Playgroud)

使用上述方法,您还可以用来store.dispatch分派异步 thunk 操作(在编写测试时可能会有所帮助)

或者使用useAppDispatch钩子

connect或使用中的老式消费者功能react-redux

它会在所有情况下为您提供正确的类型。

我个人大多数时候更喜欢推理类型声明,但有时由于外部或内部原因我们别无选择。

我希望这个答案有帮助。谢谢 :)


Jim*_*yle 18

这对我有用

import {ThunkDispatch} from "@reduxjs/toolkit";

const dispatch = useDispatch<ThunkDispatch<any, any, any>>();
Run Code Online (Sandbox Code Playgroud)


awd*_*son 14

对我来说,解决方案是更严格地遵循 RTK 文档示例。

所以使用concat...

const store = configureStore({
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware().concat(FooApi.middleware, apiErrorMiddleware),
  ...rest_of_the_config,
});
Run Code Online (Sandbox Code Playgroud)

...而不是分散数组...

const store = configureStore({
  middleware: (getDefaultMiddleware) =>
    [...getDefaultMiddleware(), FooApi.middleware, apiErrorMiddleware],
  ...rest_of_the_config,
});
Run Code Online (Sandbox Code Playgroud)


Jos*_*Jos 13

对我来说最简单的解决方案是替换:

const dispatch = useDispatch();
Run Code Online (Sandbox Code Playgroud)

和:

const dispatch = useDispatch<any>();
Run Code Online (Sandbox Code Playgroud)

  • 这是我见过的最糟糕的解决方案。我们使用 typescript 来拥有类型,而不是使用 any (12认同)

Ter*_*nat 8

编辑!

由于评论中提到,redux工具包实际上默认添加了Thunk,因此Phry的答案更准确。我无法删除已接受的答案,因此此编辑就足够了。

我提供的答案将删除自动添加的其他中间件!

问题是您实际上缺少存储配置内的 thunk 中间件。只需添加导入thunkMiddleware并将其添加到middleware配置中的数组中即可。由于未添加中间件,调度不会接受 Thunk Action,因为 redux 不支持它。

import thunkMiddleware from 'redux-thunk';

export const store = configureStore({
    reducer: {
        auth: authReducer
    },
    middleware: [thunkMiddleware],
});
Run Code Online (Sandbox Code Playgroud)

  • Thunk 是在 `configureStore` 调用时自动添加的 - 这种方法不会添加 thunk,但实际上删除了其他中间件。请不要这样做。 (7认同)