如何在打字稿中使用中间件键入 redux thunk
Posted
技术标签:
【中文标题】如何在打字稿中使用中间件键入 redux thunk【英文标题】:How to type redux thunk with middleware in typescript 【发布时间】:2021-06-29 09:35:20 【问题描述】:所以我有一个 SPFx webpart(使用打字稿)并添加了 Redux。现在一切正常,但是需要键入 thunk 函数,我不知道如何键入它们。
所以这是我要调度的操作:
export const setListByMiddelware:any = (listId:string) => (dispatch, getState) =>
dispatch(listIdAdded(listId));
dispatch(spApiCallBegan(
method: GET_LIST_ITEMS,
options:
listId
,
onSuccess: itemsAdded.type
));
这是执行 SP 调用的 SharePoint 中间件:
import SP from '../../services/SharePointService';
import * as actions from '../SP_API';
const api = store => next => async action =>
if(action.type !== actions.spApiCallBegan.type)
next(action);
return;
const method, options, onSuccess, onError, onStart = action.payload;
if(onStart)
store.dispatch( type: onStart );
next(action);
try
const result = await SP[method](options);
store.dispatch(actions.spApiCallSuccess(result));
if(onSuccess)
store.dispatch(
type: onSuccess,
payload: result
);
catch(ex)
store.dispatch(actions.spApiCallFailed(ex.message));
if(onError)
store.dispatch(
type: onError,
payload: ex.message
);
export default api;
现在你可以看到我通过简单地将 thunk 输入到any
解决了这个问题,并且效果很好,但我想强烈输入它,因为这些是我的组件的功能实际使用。
这是我正在使用的堆栈: redux@4.0.5 react-redux@7.2.3 @reduxjs/toolkit@1.5.1
我在输入 Redux 时遇到了真正的麻烦,正如你所看到的,我或多或少地放弃了这一点,而谷歌在这方面并没有多大帮助。因此,我的 Redux 代码大部分是无类型的。
至于打字稿,我想我使用的是 TS 3.3 自带的 SPFx 1.11.0,我使用的是 SPFx 版本。
编辑 正如 markerikson 所指出的那样,我已经阅读了有关在此处输入 Redux 的官方 Redux 文档: https://redux.js.org/recipes/usage-with-typescript#type-checking-middleware
但是当我实现它时,我得到:Type '(listId: string) => (dispatch: any, getState: any) => void' is notassignable to type 'ThunkAction
这是我正在使用的商店设置:
import configureStore, getDefaultMiddleware from '@reduxjs/toolkit';
import listRedurcer, IListSate from './lists';
import SP_API from './middleware/SP_API';
const store = configureStore(
reducer: listRedurcer,
middleware: [
...getDefaultMiddleware(),
SP_API
],
devTools :
name: 'ReduxList'
);
// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>;
// Inferred type: posts: PostsState, comments: CommentsState, users: UsersState
export type AppDispatch = typeof store.dispatch;
export default store;
对于 thunk,我也使用了这个 ThunkAction<void, RootState, string, AnyAction>
,但我得到了同样的错误。
【问题讨论】:
【参考方案1】:Redux docs "Usage with TypeScript" page specifically covers typing middleware and thunks:
自定义中间件如下所示:
import Middleware from 'redux'
import RootState from '../store'
export const exampleMiddleware: Middleware<
, // Most middleware do not modify the dispatch return value
RootState
> = storeApi => next => action =>
const state = storeApi.getState() // correctly typed as RootState
对于重击:
import AnyAction from 'redux'
import sendMessage from './store/chat/actions'
import RootState from './store'
import ThunkAction from 'redux-thunk'
export const thunkSendMessage = (
message: string
): ThunkAction<void, RootState, unknown, AnyAction> => async dispatch =>
const asyncResp = await exampleAPI()
dispatch(
sendMessage(
message,
user: asyncResp,
timestamp: new Date().getTime()
)
)
function exampleAPI()
return Promise.resolve('Async Chat Bot')
更新
听起来你想像这样使用ThunkAction
:
export const setListByMiddelware : ThunkAction = (listId:string) => (dispatch, getState) =>
这是不正确的。 setListByMiddelware
不是 ThunkAction
- 它返回 ThunkAction
。正确的用法是:
export const setListByMiddelware = (listId:string) : ThunkAction => (dispatch, getState) =>
另外,你的 middleware
参数是错误的:
middleware
参数应该是一个接受 getDefaultMiddleware
作为其参数的回调
然后您应该调用它,并使用数组的 prepend
和 concat
方法来设置正确的类型:
const store = configureStore(
reducer: listRedurcer,
middleware: getDefaultMiddleware => getDefaultMiddleware().concat(SP_API),
devTools :
name: 'ReduxList'
);
见https://redux-toolkit.js.org/usage/usage-with-typescript#correct-typings-for-the-dispatch-type
【讨论】:
所以我确实阅读了文档,也许我应该澄清一下。无论如何,当我使用ThunkAction<void, RootState, unknown, AnyAction>
类型时,我会收到以下错误 Type '(listId: string) => (dispatch: any, getState: any) => void' is not assignable to type 'ThunkActionThunkAction<void, RootState, string, AnyAction>
显示你在哪里使用ThunkAction
类型?
是的,我尝试使用它,但我想我使用的是错误的,当我将它应用到setListByMiddelware
thunk 时,我只是得到了上面的错误。
问题似乎是他们不能使用RootState
来键入中间件,同时还从store
派生RootState
类型,因为这是循环的(因为store
取决于中间件)。我建议明确输入RootState
。你有更好的主意吗?
是的,在这种情况下,解决方法是编写一个单独的rootReducer
函数,然后执行type RootState = ReturnType<typeof rootReducer>
,而不是来自store.getState
。【参考方案2】:
ThunkAction<void, RootState, string, AnyAction>
如果你一次性创建了你的 thunk 是合适的,比如setListByMiddelware=(dispatch, getState, listId:string)=>
,但setListByMiddelware
本身不是一个 thunk,它更像是一个 thunk 工厂,所以你需要它的类型来反映它,试试
const setListByMiddelware:(listId:string)=>ThunkAction<void, RootState, never, AnyAction> =
(listId:string) => (dispatch, getState) =>
【讨论】:
当我尝试您的解决方案时,我得到了 “ThunkActiondispatch
输入不正确,试试dispatch:Dispatch
同样的问题,这是我尝试过的实现:export const setListByMiddelware:(listId:string)=>ThunkAction<void, RootState, never, AnyAction> = (listId:string) => (dispatch:Dispatch, getState) => /* thunk code */
和错误一模一样?..试试dispatch:ThunkDispatch<RootState,never, AnyAction>
也许?
是的,有效,但很抱歉我不知道接受谁的答案,因为我从所有提交的答案中得到了答案【参考方案3】:
'api'在自己的类型注解中被直接或间接引用。
您收到此错误是因为中间件类型取决于派生自store
的RootState
类型。但是store
类型取决于中间件,所以你有一个循环类型。
解决此问题的一种方法是定义RootState
的类型,而不使用store
。在你的情况下,你的整个减速器是listReducer
,所以你可以这样做:
export type RootState = ReturnType<typeof listReducer>;
这将适用于@markerikson 建议的api
类型
const api: Middleware<, RootState> = store => next => async action =>
setListByMiddleware
是一个返回类型 是ThunkAction
的函数。函数本身不是ThunkAction
。
export const setListByMiddelware = (
listId: string
): ThunkAction<void, RootState, never, AnyAction> => (dispatch, getState) =>
dispatch(listIdAdded(listId));
dispatch(
spApiCallBegan(
method: GET_LIST_ITEMS,
options:
listId
,
onSuccess: itemsAdded.type
)
);
;
【讨论】:
以上是关于如何在打字稿中使用中间件键入 redux thunk的主要内容,如果未能解决你的问题,请参考以下文章