使用 preloadedState 时生成 Redux Toolkit TypeScript 类型

Generating Redux Toolkit TypeScript types when using preloadedState

我正在尝试设置我的测试环境,其中包括 React 测试库、Redux 工具包、RTK 查询和 TypeScript,但我 运行 遇到了一个我无法解决的问题。

我想不通的主要问题是如何在提供 preloadedState.

时生成 AppDispatch 类型 as explained in the documentation here

按照 RTK 文档直接使用 configureStore() 没问题,因为商店是在模块内部创建的:

const store = configureStore({
  reducer: {
    home: homeReducer,
    [homeApi.reducerPath]: homeApi.reducer,
  },
  middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(
    homeApi.middleware,
  ),
});

export type RootState = ReturnType<typeof store.reducer>;
export type AppDispatch = typeof store.dispatch; // not a problem as store exists here

export const useAppDispatch = () => useDispatch<AppDispatch>();
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;

export default store;

但是,这样做很难将 preloadedState 值传递给 configureStore() 并保留生成的类型。如果我提取减速器并使用 combineReducers() 我可以从那里生成 RootState,但我仍然无法弄清楚如何导出 AppDispatch 因为 store.dispatch 直到商店已创建,为了通过 preloadedState 我需要延迟商店的创建。

export const rootInitialState: Pick<RootState, 'home'> = {
  home: homeInitialState,
};

const reducer = combineReducers({
  home: homeReducer,
  [homeApi.reducerPath]: homeApi.reducer,
});

export type RootState = ReturnType<typeof reducer>;

// this is the problem as store is created externally to this module,
// so how can I extract this type now?
export type AppDispatch = typeof store.dispatch; 

export const useAppDispatch = () => useDispatch<AppDispatch>();
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;

export const createStore = (preloadedState: Partial<RootState>) => configureStore({
  reducer,
  preloadedState,
  middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(
    homeApi.middleware,
  ),
});

这真的可以做到吗?在这一点上,我完全被难住了,所以如果有人能提供解决方案或让我摆脱痛苦,我将不胜感激。

很简单,你只需要改变文件中声明的顺序并增加一个检查级别。

关键是虽然我们还没有真正的商店,但我们确实有 createStore,其中 returns 是新的商店实例。 TS 可以计算出“这个函数返回值的类型”,所以我们可以用它来代替:

export const createStore = (preloadedState: Partial<RootState>) => configureStore({
  reducer,
  preloadedState,
  middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(
    homeApi.middleware,
  ),
});

// 1) Take the type of `createStore`
// 2) Figure out the return type of that function, which is a store
// 3) Look up the type of the `dispatch` field in that returned store type
export type AppDispatch = ReturnType<typeof createStore>['dispatch'];