Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to automatically generate typescript interfaces for redux connected components

Is there a way to automatically extend the interface of a connected component using the types of mapStateToProps and mapDispatchToProps? For example, the following code:

interface ComponentProps {
  state?: State;
  action?: (id: string) => void;
}

const mapStateToProps = (state: any) => ({
  state: state,
});

const mapDispatchToProps = (dispatch: any) => ({
  action: (id: string) => dispatch(Action),
});

const Component = (props: ComponentProps) => <div>...</div>;

export const ConnectedComponent = connect(
  mapStateToProps,
  mapDispatchToProps,
)(Component);

requires me to add the state and action as optional props to my ComponentProps in order to make use of them in my component since the props will be assigned by the connect HOC.

When using something like materialUI and its withStyles HOC, we can use WithStyles<typeof styles> to automatically add classes prop (with exact keys depending on styles) to our interface like

ComponentProps extends WithStyles<typeof styles> {
  actualProps: any;
}

const ConnectedComponent = withStyles(styles)(Component);

Would it be possible to do the same for connect?

like image 363
ManavM Avatar asked Nov 22 '25 05:11

ManavM


1 Answers

Here is how it's done in the react-redux-typescript-guide:

import Types from 'MyTypes';
import { bindActionCreators, Dispatch } from 'redux';
import { connect } from 'react-redux';
import * as React from 'react';

import { countersActions } from '../features/counters';

// Thunk Action
const incrementWithDelay = () => async (dispatch: Dispatch): Promise<void> => {
  setTimeout(() => dispatch(countersActions.increment()), 1000);
};

const mapStateToProps = (state: Types.RootState) => ({
  count: state.counters.reduxCounter,
});

const mapDispatchToProps = (dispatch: Dispatch<Types.RootAction>) =>
  bindActionCreators(
    {
      onIncrement: incrementWithDelay,
    },
    dispatch
  );

type Props = ReturnType<typeof mapStateToProps> &
  ReturnType<typeof mapDispatchToProps> & {
    label: string;
  };

export const FCCounter: React.FC<Props> = props => {
  const { label, count, onIncrement } = props;

  const handleIncrement = () => {
    // Thunk action is correctly typed as promise
    onIncrement().then(() => {
      // ...
    });
  };

  return (
    <div>
      <span>
        {label}: {count}
      </span>
      <button type="button" onClick={handleIncrement}>
        {`Increment`}
      </button>
    </div>
  );
};

export const FCCounterConnectedBindActionCreators = connect(
  mapStateToProps,
  mapDispatchToProps
)(FCCounter);

You should use ReturnType helper:

type Props = ReturnType<typeof mapStateToProps> & ReturnType<typeof mapDispatchToProps> {
  label: string;
};
like image 73
teimurjan Avatar answered Nov 23 '25 20:11

teimurjan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!