Monday, July 31, 2017

Redux combineReducers compiler error

If a Redux action is added with properties other than the type property, here it's payload..

export interface UserActions extends Action {
    type: UserKind;
    payload: UserPayload;

..TypeScript will raise an error on combineReducers:

To fix the compilation error, make the Redux action property be optional:

export interface UserActions extends Action {
    type: UserKind;
    payload?: UserPayload;


However, TypeScript won't be able to catch missed properties, it won't raise an error that we didn't pass the payload property on User 6:

To fix that, remove the optional indicator on Redux action:

export interface UserActions extends Action {
    type: UserKind;
    payload: UserPayload;

Result, TypeScript is now able to catch missed properties:

However, we are back to this error on combineReducers:

To comply with combineReducers requirement of Reducer actions containing just a type property only, create another interface that has optional properties (e.g., payload), and use that for the Redux reducer's action parameter (UserActionsNoPayload). And then on UserActions, inherit UserActionsNoPayload from UserActions:

Now, no more combineReducers compilation error, and the compiler is still able to catch missed properties:

Here are the TypeScript definitions for the routeToUser:

export interface StateProps {
    user: Dto.Client.User;
    component: Component;
    counter: Dto.Client.Counter;

export interface ActionProps {
    routeToUser: UserDispatcher;
    doCounter: CounterDispatcher;

interface Props extends StateProps, ActionProps {

export type Dispatcher = (action: UserActions | CounterActions) => void;
export type UserDispatcher = (action: UserActions) => void;
export type CounterDispatcher = (action: CounterActions) => void;

export default class ReduxFirstRouterApp extends React.Component<Props, {}> {

And here is how are the states and dispatchers are mapped as properties to a component via Redux's connect:
const mapStateToProps = ({user, component, counter}: StateProps) => ({user, component, counter});

const mapDispatchToProps = (dispatch: Dispatcher): ActionProps => ({
    routeToUser: (action: UserActions) => dispatch(action),
    doCounter: (action: CounterActions) => dispatch(action)

this.AppContainer = connect(mapStateToProps, mapDispatchToProps)(ReduxFirstRouterApp);

Happy Coding!


At first, I tried creating UserActions with complete properties, and then made UserActionsNoPayload inherits UserActions and define payload as optional on UserActionsNoPayload; however, it's a compiler error:

No comments:

Post a Comment