【发布时间】:2019-10-23 04:34:49
【问题描述】:
我正在将 React Native 应用程序转换为 TypeScript,但在商店外调度 thunk 操作时遇到问题。以下是我的商店目前的设置方式:
store/index.ts
import { createStore, applyMiddleware, combineReducers, Reducer, Store } from 'redux';
import thunk, { ThunkMiddleware } from 'redux-thunk';
export interface State { ... }
export interface ActionTypes { ... } // All of the non-thunk actions
const reducer: Reducer<State> = combineReducers({ ... });
export default (): Store<State> => {
return applyMiddleware(
thunk as ThunkMiddleware<State, ActionTypes>
)(createStore)(reducer);
}
index.tsx
import { Provider } from 'react-redux';
import createStore from './store/index';
import { registerStore } from './store/registry';
const store = createStore();
registerStore(); // Registers the store in store/registry.ts
AppRegistry.registerComponent(appName, () => () => (
<Provider store={store}>
<App />
</Provider>
));
store/registry.ts
import { Store } from 'redux';
import { State } from './index';
let store: Store<State>;
export const registerStore = (newStore: Store<State>) => {
store = newStore;
};
export const getStore = () => store;
所以当商店创建时,我将它存储在商店注册表中,这样我就可以从任何地方调用getStore()。
这在组件(我不使用注册表)中运行良好,例如在我的 App.tsx 中:
import { connect } from 'react-redux';
import { ThunkDispatch } from 'redux-thunk';
import { checkAuthStatus as checkAuthStatusAction } from './store/modules/auth/actions';
import { ActionTypes, State as AppState } from './store/index';
interface State = { ... }
interface StateProps { ... }
interface DispatchProps {
checkAuthStatus: () => Promise<boolean>;
}
type Props = StateProps & DispatchProps;
class App extends Component<Props, State> {
async componentDidMount() {
const promptSkipped: boolean = await checkAuthStatus(); // Thunk action, works fine!
}
...
}
const mapStateToProps = ...;
const mapDispatchToProps = (dispatch: ThunkDispatch<AppState, null, ActionTypes>): DispatchProps => ({
checkAuthStatus: () => dispatch(checkAuthStatusAction()),
});
export default connect<StateProps, DispatchProps, {}, AppState>(
mapStateToProps,
mapDispatchToProps,
)(App);
当我想使用注册表来调度一个 thunk 动作时,问题就来了:
lib/notacomponent.ts
import { getStore } from '../store/registry';
import { checkAuthStatus, setLoggedIn } from '../store/modules/auth/actions'
const someFunction = () => {
const store = getStore();
const { auth } = store.getState(); // Accessing state works fine!
store.dispatch(setLoggedIn(true)); // NON-thunk action, works fine!
store.dispatch(checkAuthStatus()); // Uh-oh, thunk action doesn't work.
}
这给了我错误:
Argument of type 'ThunkAction<Promise<boolean>, State, null, Action<any>>' is
not assignable to parameter of type 'AnyAction'.
Property 'type' is missing in type 'ThunkAction<Promise<boolean>, State, null, Action<any>>'
but required in type 'AnyAction'. ts(2345)
据我所知,使用 thunk as ThunkMiddleware<State, ActionTypes> 作为中间件允许 Redux Thunk 将 stores 调度方法替换为一种可以调度 thunk 动作和普通动作的方法。
我认为我需要以某种方式键入注册表,以便 TypeScript 可以看到调度方法 不是 只允许正常操作的默认方法。但是,我不知道如何做到这一点。我找不到任何其他人做同样事情的例子。
感谢任何帮助。
编辑:How to dispatch an Action or a ThunkAction (in TypeScript, with redux-thunk)? 的建议副本不能解决我的问题。我可以在组件内很好地调度 thunk 动作。使用上面定义的商店注册表,我只在组件之外遇到问题。
编辑 2:看来我可以在调度 thunk 操作时使用以下类型断言来消除错误:
(store.dispatch as ThunkDispatch<State, void, ActionTypes>)(checkAuthStatus())
但这是非常不切实际的。我还没有找到一种方法来做到这一点,所以 TypeScript 知道 dispatch 方法应该总是能够调度一个 thunk 动作。
【问题讨论】:
-
在查看 redux github 的问题后找到了该主题(github.com/reduxjs/redux-thunk/issues/135 - 看起来与您的情况相同)
-
@skyboyer 不幸的是,我认为这没有帮助。它在组件内工作正常。我尝试在 pierpytom 的回答中添加
(store.dispatch as ThunkDispatch<State, void, ActionTypes>),但这并没有改变任何东西。 -
嗯,这很奇怪。所以完整的调用看起来像
(store.dispatch as ThunkDispatch<State, void, ActionTypes>)(checkAuthStatus()),这给出了关于幸运type属性的相同错误,对吧?如果是的话,如何强制类型转换为(...args: any[]) => any之类的东西? -
@skyboyer 实际上,
(store.dispatch as ThunkDispatch<State, null, ActionTypes>)(checkAuthStatus())确实有效。我第一次没有将ThunkDispatch的第二个参数更改为null。我可以对商店注册表做些什么来使情况始终如此吗?对每个 thunk 动作都这样做有点 hacky
标签: javascript reactjs typescript redux redux-thunk