I have a simple reducer & action types right now. While setting up my tests, I am running into a type def issue with the return of my store
in reference to my "custom" action type declarations. I am seeing an error:
Type ‘Store<CombinedState<{ global: GlobalStateShape; }>, SetSelectedAccount >’ is not assignable to type ‘Store<any, AnyAction>’. Types of property ‘dispatch’ are incompatible
I have followed the Redux Typescript docs correctly AFAIK.
Why is SetSelectedAccount
being returned when I invoke combineReducers()
? The globalReducer
is handling action of SetSelectedAccount
.
In my test setup File where the error above occurs:
export function createTestStore(isInternal: boolean): Store {
const store: Store<CombinedState<{
global: GlobalStateShape;
}>, SetSelectedAccount> = createStore(rootReducer, { global:
getGlobalInitialState(isInternal) });
return store;
}
src/reducer.ts
export const rootReducer: Reducer<CombinedState<{
global: GlobalStateShape;
}>, SetSelectedAccount> = combineReducers({
global: globalReducer,
});
src/store.ts
const composedEnhancer = composeWithDevTools(
applyMiddleware()
);
export const store: Store<CombinedState<{
global: GlobalStateShape;
}>, SetSelectedAccount> = createStore(rootReducer, composedEnhancer);
global_reducer.ts:
export const globalReducer = (
state = GLOBAL_INITIAL_STATE,
action: GlobalActionTypes
): GlobalStateShape =>
produce(state, draft => {
switch (action.type) {
case GlobalActions.SET_SELECTED_ACCOUNT: {
draft.selectedAccountId = action.payload.accountId;
break;
}
}
});
actions.ts
const SET_SELECTED_ACCOUNT = 'SET_SELECTED_ACCOUNT';
export const GlobalActions = {
SET_SELECTED_ACCOUNT,
};
export interface SetSelectedAccount {
type: typeof SET_SELECTED_ACCOUNT;
payload: { accountId: string; selectedApp: AppsList };
}
export type GlobalActionTypes = SetSelectedAccount;
FWIW, if I add a 2nd Action, then SetSelectedAccount
turns into returned type above of GlobalActionTypes
which is the same result & error message about mismatching dispatch
Thank you!
The problem is the return type on your createTestStore
function. You creating a store a a specific type (Store<CombinedState<{ global: GlobalStateShape; }>, SetSelectedAccount >
) and then you are returning it as just Store
with no generics. The default type for Store
is the Store<any, AnyAction>
which you see in your error message.
You might think that this wouldn't be a problem because your store is more specific, so it should be assignable to Store
, right? But specificity gets backwards when you are dealing with function arguments like those of Dispatch
. The return type says that you are returning a store which is capable of dispatching AnyAction
, but in reality you are only capable of dispatching the type SetSelectedAccount
, so your store is not assignable to the broader type.
The easiest thing to do is just remove that return type : State
entirely. You've already typed the store
variable which you are returning, so you don't really need it.
You could also move the type annotation from the variable store
to the function return. FYI the redux CombinedState
utility type doesn't really do anything, CombinedState<{ global: GlobalStateShape; }>
is the same as { global: GlobalStateShape; }
export function createTestStore(isInternal: boolean): Store<{ global: GlobalStateShape; }, SetSelectedAccount> {
return createStore(rootReducer, {
global: getGlobalInitialState(isInternal)
});
}