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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/43013204/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 04:23:09  来源:igfitidea点击:

How to dispatch an Action or a ThunkAction (in TypeScript, with redux-thunk)?

typescriptreduxredux-thunk

提问by pleasedesktop

Say I have code like so:

假设我有这样的代码:

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
}

...I get this error from the TypeScript compiler:

...我从 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>'.

I believe the problem is because of the way the redux-thunktype definition file augments the reduxDispatchinterface and the inability for TypeScript to know which definition of Dispatchto use.

我相信问题是因为redux-thunk类型定义文件增强reduxDispatch接口的方式以及 TypeScript 无法知道使用哪个定义Dispatch

Is there a way around this?

有没有解决的办法?

采纳答案by Michael Peyper

I think you are correct in that despite being able to handle both types, typescript cannot work out which overload to use.

我认为您是正确的,尽管能够处理这两种类型,但打字稿无法确定使用哪种重载。

I think the best option for you is to cast back to the desired type when calling dispatch

我认为对您来说最好的选择是在调用时转换回所需的类型 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);
  }
}

I hope I'm wrong and there is a better way to achieve this.

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

回答by pierpytom

ThunkAction signature changed with latest version (now is ThunkAction<void, Your.Store.Definition, void, AnyAction>) and unless some evil double casting (action as {} as Action), the more elegant way I found is to define the redux dispatch as a ThunkDispatch like this:

ThunkAction 签名随着最新版本(现在是ThunkAction<void, Your.Store.Definition, void, AnyAction>)而变化,除非一些邪恶的双重转换(action as {} as Action),我发现更优雅的方法是将 redux dispatch 定义为像这样的 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;

}

In case someone else is looking for an updated answer! ^^

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

回答by Auth Infant

Time has passed and many things have changed since this question and various answers were posted. However, I found that none of the answers seemed satisfactory to me because the first two (michael-peyper and pierpytom) involved recasting/redefining which felt weird. The third (joaoguerravieira) seemed better since it didn't involve either of those, but it was unclear, to me at least, how it solved the problem.

自从这个问题和各种答案被发布以来,时间已经过去了,很多事情都发生了变化。然而,我发现没有一个答案让我满意,因为前两个(michael-peyper 和 pierpytom)涉及重铸/重新定义,这感觉很奇怪。第三个(joaoguerravieira)似乎更好,因为它不涉及其中任何一个,但至少对我来说不清楚它是如何解决问题的。

This is what seemed most helpful to me when I ran into a problem which I think was practically identical to this: how to get a properly typed "dispatch" method on the created redux store. That is, how to get the TypeScript compiler to agree that store.dispatch could dispatch either Actions orThunkActions. Even if this is not exactly the same problem being asked about in the original question (but I think it might be), all search engine queries about my problem kept leading me back to this post so I thought it might be helpful to put my solution here.

当我遇到一个我认为实际上与此相同的问题时,这似乎对我最有帮助:如何在创建的 redux 存储上获得正确类型的“调度”方法。也就是说,如何让 TypeScript 编译器同意 store.dispatch 可以调度 ActionsThunkActions。即使这不是在原始问题中被问到的完全相同的问题(但我认为可能是),所有关于我的问题的搜索引擎查询一直引导我回到这篇文章,所以我认为提出我的解决方案可能会有所帮助这里。

I have always found it super difficult to find the right types to use for things when using redux (maybe I'm just dumb) so for a long time I always just created my store like this:

我一直发现在使用 redux 时很难找到正确的类型来用于事物(也许我只是愚蠢)所以很长一段时间我总是像这样创建我的商店:

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

...which always put me in the situation where I could call store.dispatch on thunks but the TypeScript compiler yelled at me even though it would still work at runtime. Bits of each answer finally lead me to what I believe is the most up-to-date and no-casting way of solving the problem.

...这总是让我处于可以在 thunk 上调用 store.dispatch 但 TypeScript 编译器对我大喊大叫的情况,即使它在运行时仍然可以工作。每个答案的点点滴滴最终让我找到了我认为是解决问题的最新且无需强制转换的方法。

The typing of the dispatch method on the store object is dictated by what the call to redux's createStore returns. In order to have the right type on the store's dispatch method, you have to set the type parameters correctly on the call to applyMiddleware (which you either directly or eventually pass as the third parameter to createStore). @joaoguerravieira's answer led me to look in this direction. In order to get the dispatch method to have the right type to dispatch either ThunkAction or Action, I had to call createStore/applyMiddleware like this:

store 对象上的 dispatch 方法的类型取决于对 redux 的 createStore 的调用返回的内容。为了在 store 的 dispatch 方法上拥有正确的类型,您必须在调用 applyMiddleware 时正确设置类型参数(您直接或最终将其作为第三个参数传递给 createStore)。@joaoguerravieira 的回答让我朝这个方向看。为了让 dispatch 方法拥有正确的类型来调度 ThunkAction 或 Action,我不得不像这样调用 createStore/applyMiddleware:

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

where

在哪里

type DispatchFunctionType = ThunkDispatch<StateType, undefined, AnyAction>

By doing this, I got a store of this type:

通过这样做,我得到了这种类型的商店:

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

...which gets me a store.dispatch function of this type:

...这让我得到了这种类型的 store.dispatch 函数:

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

...which can successfully dispatch an Action or a ThunkAction without yelling about type and without any redefinitions/casting.

...它可以成功地分派 Action 或 ThunkAction ,而无需大喊大叫类型,也无需任何重新定义/转换。

Properly setting the type parameters on the call to applyMiddleware is critical!

在调用 applyMiddleware 时正确设置类型参数至关重要!

回答by joaoguerravieira

These are the correct typings: https://github.com/reduxjs/redux-thunk/blob/master/test/typescript.ts

这些是正确的类型:https: //github.com/reduxjs/redux-thunk/blob/master/test/typescript.ts

Most notably:

最为显着地:

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

applyMiddlewarewill already override the dispatch with a ThunkDispatch.

applyMiddleware将已经用ThunkDispatch.