使用 preloadedState 时生成 Redux Toolkit TypeScript 类型

Dre*_*rew 3 typescript redux redux-toolkit

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

我无法弄清楚的主要问题是AppDispatch如何提供preloadedState.

按照 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;
Run Code Online (Sandbox Code Playgroud)

但是,这样做会导致难以将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,
  ),
});
Run Code Online (Sandbox Code Playgroud)

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

mar*_*son 6

很简单,您只需更改文件中声明的顺序并添加多一级的检查即可。

关键是,虽然我们还没有真正的商店,但我们确实有createStore,它返回新的商店实例。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'];
Run Code Online (Sandbox Code Playgroud)