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?
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;
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With