如何将 Redux 4.0 TypeScript 绑定与 redux-thunk 结合使用

How to use Redux 4.0 TypeScript bindings with redux-thunk

我在使用 Redux 4.0 的新 TS 绑定和 redux-thunk 时遇到问题。我通过转换基本的 Redux "Todo List" example to TypeScript (repo here), and making the Add Todo action a thunk. The problem is the same as reported here 重现了这个问题:Argument of type 'ThunkAction' is not assignable to parameter of type 'AnyAction'。 属性 'type' 在类型 'ThunkAction' 中缺失。

基本上,我可以让它工作,但我在一些我认为不应该使用的地方使用 any。一个地方是 index.tsx#L14,我在其中将 thunk 中间件添加到商店:

const store = createStore(
  rootReducer,
  applyMiddleware(thunk as ThunkMiddleware<IRootState, any>)
);

如果我在那里使用 any 以外的任何东西,那么下一行会抛出错误:

store.dispatch(addTodo('Use redux-thunk'));

另一个地方是AddTodo.tsx#L7,我在这里声明了由connect函数注入的dispatch prop:

interface IAddTodoProps {
  dispatch: Dispatch<any>;
}

const AddTodo = ({ dispatch }: IAddTodoProps) => {
  ...
}
export default connect()(AddTodo);

在这两个地方,any 覆盖了必须扩展 Action<any> 的类型。 Action 需要一个 type 属性,这当然是 thunk 所没有的。我如何声明这些类型以便 dispatch 函数接受一个 thunk?

Related question
Relevant PR

diff --git a/src/containers/AddTodo.tsx b/src/containers/AddTodo.tsx
index e49ac4a..20a93d6 100644
--- a/src/containers/AddTodo.tsx
+++ b/src/containers/AddTodo.tsx
@@ -1,10 +1,12 @@
 import * as React from 'react';
 import { connect } from 'react-redux';
-import { Dispatch } from 'redux';
+import { ThunkDispatch } from 'redux-thunk';
+import { AnyAction } from 'redux';
 import { addTodo } from '../actions';
+import { IRootState } from '../reducers/index';

 interface IAddTodoProps {
-  dispatch: Dispatch<any>;
+  dispatch: ThunkDispatch<IRootState,any,AnyAction>;
 }

 const AddTodo = ({ dispatch }: IAddTodoProps) => {

这个问题(以及许多其他问题)的答案原来是:使用 Redux Toolkit

商店设置非常简单:

// src/redux/store.ts
import { configureStore } from '@reduxjs/toolkit';
import reducer from './reducers';

const store = configureStore({ reducer });

export type AppDispatch = typeof store.dispatch;

export default store;

然后在使用 react-redux 中的 useDispatch 挂钩时,只需将其键入 AppDispatch:

// src/components/App.tsx
import { useDispatch } from 'react-redux';
import { AppDispatch } from '../redux/store';

const App = () => {
  const dispatch: AppDispatch = useDispatch();
  // ...
}