如何分派Action或ThunkAction(在TypeScript中,使用redux-thunk)?

g52tjvyc  于 2023-08-05  发布在  TypeScript
关注(0)|答案(6)|浏览(148)

假设我有这样的代码:

import { Action, Dispatch } from 'redux';
import { ThunkAction } from 'redux-thunk';

interface StateTree {
  field: string;
}

function myFunc(action: Action | ThunkAction<void, StateTree, void>,
                dispatch: Dispatch<StateTree>) {
  dispatch(action); // <-- This is where the error comes from
}

字符串
...我从TypeScript编译器得到这个错误:

ERROR in myFile.ts:x:y
TS2345: Argument of type 'Action | ThunkAction<void, StateTree, void>' is not assignable to parameter of type 'Action'.
  Type 'ThunkAction<void, StateTree, void>' is not assignable to type 'Action'.
  Property 'type' is missing in type 'ThunkAction<void, StateTree, void>'.


我认为问题是因为redux-thunk类型定义文件扩展reduxDispatch接口的方式,以及TypeScript无法知道使用Dispatch的哪个定义。
有办法解决吗?

44u64gxh

44u64gxh1#

ThunkAction签名随着最新版本而改变(现在是ThunkAction<void, Your.Store.Definition, void, AnyAction>),除非有一些邪恶的双重转换(action as {} as Action),我发现更优雅的方法是将redux调度定义为ThunkDispatch,如下所示:

import { applyMiddleware, Store, createStore, AnyAction } from 'redux';
import logger from 'redux-logger';
import thunk, { ThunkDispatch } from 'redux-thunk';

import { Redux } from '../definitions';
import rootReducer from './reducers';
import { bootstrap } from './actions';

export default function configureStore() {

    const middleware = applyMiddleware( thunk, logger );

    const store: Store<Redux.Store.Definition> = createStore(rootReducer, middleware);

    // Here the dispatch casting:
    (store.dispatch as ThunkDispatch<Redux.Store.Definition, void, AnyAction>)( bootstrap() );

    return store;

}

字符串
如果其他人正在寻找更新的答案!^^

rggaifut

rggaifut2#

时间已经过去了,自从这个问题和各种答案被张贴以来,许多事情都发生了变化。然而,我发现没有一个答案让我满意,因为前两个(michael-peyper和pierpytom)涉及重铸/重新定义,感觉很奇怪。第三个(joaoguerravieira)似乎更好,因为它不涉及这两个,但不清楚,至少对我来说,它是如何解决这个问题的。
当我遇到一个问题时,这似乎对我最有帮助,我认为这个问题实际上与此相同:如何在创建的redux store上获得正确类型的“dispatch”方法。也就是说,如何让TypeScript编译器同意store.dispatch可以调度Actions * 或ThunkActions。即使这不是完全相同的问题被问到在原来的问题(但我认为它可能是),所有的搜索引擎查询我的问题不断导致我回到这篇文章,所以我认为这可能是有帮助的,把我的解决方案在这里。
我总是发现在使用redux时很难找到合适的类型(也许我只是笨),所以很长一段时间我总是像这样创建我的商店:

createStore(
    combineReducers(stuff),
    defaultState,
    applyMiddleware(thunkMiddleware));

字符串
...这总是让我陷入这样的境地:我可以在thunks上调用store.dispatch,但TypeScript编译器对我大喊大叫,尽管它在运行时仍然可以工作。每一个答案的位最终导致我相信是最新的和无铸造的解决问题的方法。
store对象上dispatch方法的类型由调用redux的createStore返回的内容决定。为了在存储的调度方法上使用正确的类型,您必须在调用applyMiddleware时正确设置类型参数(您可以直接或最终将其作为第三个参数传递给createStore)。@joaoguerravieira的回答让我朝这个方向看。为了让dispatch方法具有正确的类型来分派ThunkAction或Action,我必须像这样调用createStore/applyMiddleware:

createStore(
    combineReducers(stuff),
    defaultState,
    applyMiddleware<DispatchFunctionType, StateType>(thunkMiddleware));


其中,

type DispatchFunctionType = ThunkDispatch<StateType, undefined, AnyAction>


通过这样做,我得到了一个这样的商店:

Store<StateType, Action<StateType>> & { dispatch: DispatchFunctionType };


...这会给我一个这样的store.dispatch函数:

Dispatch<Action<any>> & ThunkDispatch<any, undefined, AnyAction>


...它可以成功地调度一个Action或ThunkAction,而无需对类型大喊大叫,也无需任何重定义/转换。
正确设置applyMiddleware调用的类型参数是至关重要的!

kpbwa7wx

kpbwa7wx3#

以下是正确的打字:https://github.com/reduxjs/redux-thunk/blob/master/test/typescript.ts
最值得注意的是:

const store = createStore(fakeReducer, applyMiddleware(thunk as ThunkMiddleware<State, Actions>));

字符串
applyMiddleware将使用ThunkDispatch覆盖调度。

fd3cxomn

fd3cxomn4#

我认为你是正确的,尽管能够处理这两种类型,但typescript无法确定使用哪种重载。
我认为最好的选择是在调用dispatch时强制转换回所需的类型

function myFunc(action: Action | ThunkAction<void, StateTree, void>, 
                dispatch: Dispatch<StateTree>) {
  if (action instanceof ThunkAction<void, StateTree, void>) {
    dispatch(action as ThunkAction<void, StateTree, void>);
  } else {
    dispatch(action as Action);
  }
}

字符串
我希望我错了,有更好的方法来实现这一目标。

vi4fp9gy

vi4fp9gy5#

如果你正在使用Redux Toolkit的configureStore()抽象,你可以使用提供的getDefaultMiddleware()回调,它将为你提供thunk中间件和一个可以接受AnyActionThunkActionstore.dispatch

const store = configureStore({
  devTools: process.env.NODE_ENV !== 'production',
  // getDefaultMiddleware() adds redux-thunk by default
  // It also provides a properly typed store.dispatch that can accept AnyAction and ThunkAction
  // See https://redux-toolkit.js.org/api/getDefaultMiddleware
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware().concat(anyOtherMiddleware),
  preloadedState: {},
  reducer: reducers,
});

字符串
你可以在他们的文档中阅读更多关于configureStore()getDefaultMiddleware()的内容。

798qvoo8

798qvoo86#

也许我迟到了,但在我的情况下,我可以通过显式定义分派函数的类型来获得它

const rootReducer = combineReducers({......})

type DispatchFunctionType = ThunkDispatch<RootState, undefined, AnyAction>

const store = createStore(rootReducer, composeWithDevTools(applyMiddleware<DispatchFunctionType, RootState>(thunk)));
export type RootState = ReturnType<typeof rootReducer>;

export default store;

字符串

相关问题