替换Reducer后如何获取Redux Toolkit Store的完整类型?
解决Redux Toolkit动态替换Reducer后的TypeScript类型问题
当你用replaceReducer动态扩展Reducer后,TypeScript静态类型系统无法自动感知store状态类型的变化,导致store.getState()仍返回初始的RootState类型。下面提供两种可行的解决方法:
方法一:用模块扩展(Module Augmentation)动态扩展RootState类型
这种方法不需要修改store的导出方式,直接通过TypeScript的模块扩展能力来更新RootState类型:
1. 修改core.ts中的RootState定义
将原本基于store.getState()返回值生成的类型,改成可扩展的接口:
// core.ts import { combineReducers, configureStore } from '@reduxjs/toolkit'; import { app } from './app'; import { user } from './user'; const coreReducers = { app, user, }; // 先定义核心状态的基础类型 export type CoreState = ReturnType<typeof combineReducers(coreReducers)>; // 定义可扩展的RootState接口 export interface RootState extends CoreState {} const store = configureStore({ reducer: combineReducers(coreReducers), }); export default store; export { coreReducers }; export type AppDispatch = typeof store.dispatch; export function mapStateToProps<C extends R, R, S extends RootState>(component: C, mapState: (state: S) => R): Unsubscribe { // ... 原有逻辑 }
2. 在app.ts中扩展RootState接口
通过declare module语法扩展core.ts中导出的RootState接口,添加新增reducer对应的状态类型:
// app.ts import { combineReducers, createSlice } from '@reduxjs/toolkit'; import store, { coreReducers, RootState } from 'src/core/store'; const newReducerSlice = createSlice({ name: 'newReducer', reducers: {}, initialState: {}, }); const appReducers = { newReducer: newReducerSlice.reducer, }; const appReducer = combineReducers({ ...coreReducers, ...appReducers, }); store.replaceReducer(appReducer); // 扩展RootState接口,添加newReducer的类型 declare module 'src/core/store' { interface RootState { newReducer: ReturnType<typeof newReducerSlice.reducer>; } } export type AppState = ReturnType<typeof appReducer>; export function mapStateToProps<C extends R, R, S extends AppState>(component: C, mapState: (state: S) => R): Unsubscribe { return msp(component, mapState); }
这样修改后,store.getState()的返回值类型会自动更新为扩展后的RootState,包含newReducer属性。
方法二:重新导出带有正确类型的Store实例
如果不想用模块扩展,可以在替换Reducer后,重新导出一个带有正确状态类型的Store实例:
1. 在app.ts中重新导出类型化的store
// app.ts import { combineReducers, createSlice, Store } from '@reduxjs/toolkit'; import store, { coreReducers, mapStateToProps as msp } from 'src/core/store'; const newReducerSlice = createSlice({ name: 'newReducer', reducers: {}, initialState: {}, }); const appReducers = { newReducer: newReducerSlice.reducer, }; const appReducer = combineReducers({ ...coreReducers, ...appReducers, }); store.replaceReducer(appReducer); export type AppState = ReturnType<typeof appReducer>; // 将原store断言为带有AppState类型的Store实例 export const appStore = store as Store<AppState>; export function mapStateToProps<C extends R, R, S extends AppState>(component: C, mapState: (state: S) => R): Unsubscribe { return msp(component, mapState); }
2. 在service.ts中导入类型化的appStore
// service.ts import { appStore } from 'src/app'; function myService() { const storeState = appStore.getState(); const { newReducer } = storeState; // 类型正确,无报错 }
为什么原有mapStateToProps可以正常工作?
因为你在app.ts中重新定义的mapStateToProps通过泛型约束S extends AppState,强制传入的mapState函数使用扩展后的AppState类型,而core.ts中的mapStateToProps允许S继承RootState,所以类型可以兼容。但原store实例的类型是在创建时就确定的,静态类型系统无法感知运行时的replaceReducer操作,所以需要手动扩展类型或重新导出类型化的实例。
内容的提问来源于stack exchange,提问作者Miquel
相关产品推荐
相关产品推荐

