redux-dynamic-modules
redux-dynamic-modules copied to clipboard
Update generic IModule interface
Please update IModule interface, so it will be possible to set Action type, e.g.
export interface IModule<State, Action = AnyAction> { /** * Id of the module / id: string; /* * Reducers for the module / reducerMap?: ReducersMapObject<State, Action >; /* * Middlewares to add to the store / middlewares?: Middleware[]; /* * These actions are dispatched immediately after adding the module in the store / initialActions?: Action[]; /* * These actions are dispatched immediatly before removing the module from the store / finalActions?: Action[]; /* * Specifies if the module is retained forever in the store */ retained?: boolean; }
Question: what shape are your actions such that they aren't compatible with redux's AnyAction interface? The AnyAction interface only requires a type field and lets any other assigned field be any.
I am using 'flux-standard-action' library typings: FSAAuto and ErrorFSAAuto. Link to typings file https://github.com/redux-utilities/flux-standard-action/blob/master/src/index.d.ts.
I have a reducer
export function appReducer(state: AppState = initialAppState, action: AppActions): AppState {...}
Where AppActions is
export type AppActions = FSAAuto<AppActionTypes.REQUEST_APP_METADATA, AppMetadataPayload> | FSAAuto<AppActionTypes.REQUEST_APP_METADATA_SUCCEED, App> | ErrorFSAAuto<AppActionTypes.REQUEST_APP_METADATA_FAILED>
In my module
export const AppModule: ISagaModule<AppAwareState> = { id: 'appModule', reducerMap: { appModule: appReducer, }, // TODO: fix typing issue sagas: [rootSaga], };
I see a TS error:
(property) IModule<AppAwareState>.reducerMap?: ReducersMapObject<AppAwareState, AnyAction> | undefined Reducers for the module
Type '{ appModule: (state: AppState | undefined, action: AppActions) => AppState; }' is not assignable to type 'ReducersMapObject<AppAwareState, AnyAction>'. Types of property 'appModule' are incompatible. Type '(state: AppState | undefined, action: AppActions) => AppState' is not assignable to type 'Reducer<AppState, AnyAction>'. Types of parameters 'action' and 'action' are incompatible. Type 'AnyAction' is not assignable to type 'AppActions'. Type 'AnyAction' is not assignable to type 'ErrorFluxStandardActionWithPayload<AppActionTypes.REQUEST_APP_METADATA_FAILED, Error, undefined>'. Property 'error' is missing in type 'AnyAction' but required in type 'ErrorFluxStandardAction<AppActionTypes.REQUEST_APP_METADATA_FAILED, Error, undefined>'.ts(2322) index.d.ts(47, 3): 'error' is declared here. Contracts.d.ts(13, 5): The expected type comes from property 'reducerMap' which is declared here on type 'ISagaModule<AppAwareState>'
Thus it would be nice to have possibility to set own action types. By default it can be set to AnyAction
@kazamov did you figure this out? If you have a repo where I can see the problem, that may better help me understand your problem.
I am encountering the same problem. I am trying to use connected-react-router and getting the following error:
TypeScript error in /myapp/src/app/store/module.ts(13,3): Type '{ router: Reducer<RouterState<History.PoorMansUnknown>, LocationChangeAction<History.PoorMansUnknown>>; }' is not assignable to type 'ReducersMapObject<AppModuleState, AnyAction>'. Types of property 'router' are incompatible. Type 'Reducer<RouterState<PoorMansUnknown>, LocationChangeAction<PoorMansUnknown>>' is not assignable to type 'Reducer<RouterState<PoorMansUnknown>, AnyAction>'. Types of parameters 'action' and 'action' are incompatible. Type 'AnyAction' is not assignable to type 'LocationChangeAction<PoorMansUnknown>'. TS2322
Here is my code:
import {ISagaModule} from 'redux-dynamic-modules-saga'
import {connectRouter, routerMiddleware, RouterState} from 'connected-react-router'
import history from 'utils/history'
const routerReducer = connectRouter(history)
interface AppModuleState {
router: RouterState,
}
const AppModule: ISagaModule<AppModuleState> = {
id: 'app',
reducerMap: {
router: routerReducer,
},
middlewares: [
routerMiddleware(history),
],
sagas: [],
}
export default AppModule
I believe this might be because of strict contravariance and the way that RouterState is defined by connected-react-router. I was able to workaround it by adding the following assertion:
import {Reducer} from 'redux'
.
.
.
const routerReducer = connectRouter(history) as Reducer<RouterState>
I don't know if the best way to handle this is to change the signature of IModule to accept a generic action type, or to just assign manually as I've done above. Just thought this might be helpful to anyone else who encounters this issue.
Hi @bloomdido.
I have found a workaround for this issue. If cast the type of "reducerMap" property to ReducersMapObject<YOUR_REDUCER_MAP_TYPE>, everything is fine. E.g.
export const RoleModule: ISagaModule<RoleAwareState> = {
id: 'roleModule',
reducerMap: {
roleModule: roleReducer,
} as ReducersMapObject<RoleAwareState>,
sagas: [rootSaga],
};
@kazamov Yeah, I think both of our solutions are about getting around Typescript's strict contravariance for callbacks.
From what I understand, the issue is that any action can always be an AnyAction, but an AnyAction cannot always be any action.
From what I understand, the issue is that any action can always be an
AnyAction, but anAnyActioncannot always be any action.
@bloomdido , This seems to be the same issue I am now encountering with putting a ThunkAction in the initialActions part of the module. Any suggestions on resolving this? I have not been able to find a way to eliminate this problem.
export const fetchToplineData = (): ThunkAction<any, any, any, AnyAction> => {
return (dispatch, getState) => {
const mockData = [{ a: 1, b: 2, c: 3, s: getState() }];
dispatch(toplineDataAvailable(mockData));
};
};
export function getToplineModule(): IModule<any> {
return {
// Unique id of the module
id: "topline",
// Maps the Store key to the reducer
reducerMap: {
topline: toplineReducer,
},
initialActions: [fetchToplineData()], // this line errors
finalActions: [],
};
}
Error Produced
TS2741: Property 'type' is missing in type 'ThunkAction<any, any, any, AnyAction>' but required in type 'AnyAction'.
From what I understand, the issue is that any action can always be an
AnyAction, but anAnyActioncannot always be any action.@bloomdido , This seems to be the same issue I am now encountering with putting a
ThunkActionin theinitialActionspart of the module. Any suggestions on resolving this? I have not been able to find a way to eliminate this problem.export const fetchToplineData = (): ThunkAction<any, any, any, AnyAction> => { return (dispatch, getState) => { const mockData = [{ a: 1, b: 2, c: 3, s: getState() }]; dispatch(toplineDataAvailable(mockData)); }; };export function getToplineModule(): IModule<any> { return { // Unique id of the module id: "topline", // Maps the Store key to the reducer reducerMap: { topline: toplineReducer, }, initialActions: [fetchToplineData()], // this line errors finalActions: [], }; }Error Produced
TS2741: Property 'type' is missing in type 'ThunkAction<any, any, any, AnyAction>' but required in type 'AnyAction'.
Hi @forgo, I described the workaround above, you should cast 'reducerMap' to proper type
Hi @kazamov , just to be clear, my error is on initialActions not the reducerMap. Not sure if that is related. I had already tried your example above casting reducerMap as ReducersMapObject<any> and ReducersMapObject<any, any> and still have this error before posting here.