Created
November 2, 2018 11:04
-
-
Save OliverJAsh/fd210d846aaf4e941346f384b6aa7ba6 to your computer and use it in GitHub Desktop.
React Redux: infer Redux props from mappers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { SFC } from 'react'; | |
import { MapDispatchToPropsParam, MapStateToPropsParam } from 'react-redux'; | |
import { StateRoot } from 'reducers/types'; | |
import { AnyAction, Dispatch } from 'redux'; | |
// | |
// Helpers | |
// | |
const createSubType = <T extends any>() => <SubType extends T>(subType: SubType) => subType; | |
// Default dispatch props for react-redux | |
type DefaultDispatchProps = { dispatch: Dispatch }; | |
// This helper function provides type inference to the `mapStateToProps` function params. | |
// We use the return type of this function to infer the `StateProps`. | |
const createMapStateToProps = <OwnProps extends {}>() => | |
createSubType<MapStateToPropsParam<any, OwnProps, StateRoot>>(); | |
// This helper function provides type inference to the `mapDispatchToProps` function params. | |
// We use the return type of this function to infer the `DispatchProps`. | |
const createMapDispatchToProps = <OwnProps extends {}>() => | |
createSubType<MapDispatchToPropsParam<any, OwnProps>>(); | |
type GetStateProps < | |
MapStateToProps extends MapStateToPropsParam < any , any , any > | |
> = MapStateToProps extends MapStateToPropsParam<infer StateProps, any, any> ? StateProps : never; | |
type GetDispatchProps < | |
MapDispatchToProps extends MapDispatchToPropsParam < any , any > | |
> = MapDispatchToProps extends MapDispatchToPropsParam<infer DispatchProps, any> | |
? DispatchProps | |
: never; | |
type GetReduxProps < | |
MapStateToProps extends MapStateToPropsParam < any , any , any > = null , | |
MapDispatchToProps extends MapDispatchToPropsParam < any , any > = DefaultDispatchProps | |
> = GetStateProps<MapStateToProps> & GetDispatchProps<MapDispatchToProps>; | |
// | |
// Begin example | |
// | |
type Photo = { title: string }; | |
// Selector | |
declare const getPhotoById: (state: StateRoot, photoId: string) => Photo; | |
// Action creator | |
declare const likePhoto: (photoId: string) => AnyAction; | |
type OwnProps = { | |
photoId: string; | |
}; | |
// Infer the connected props from the mapping functions | |
type ReduxProps = GetReduxProps<typeof mapStateToProps, typeof mapDispatchToProps>; | |
type Props = OwnProps & ReduxProps; | |
export const LikePhotoButton: SFC<Props> = ({ photoId, photo, likePhoto }) => ( | |
<button | |
onClick={() => { | |
likePhoto(photoId); | |
}} | |
> | |
{photo.title} | |
</button> | |
); | |
const mapStateToProps = createMapStateToProps<OwnProps>()((state, ownProps) => ({ | |
photo: getPhotoById(state, ownProps.photoId), | |
})); | |
const mapDispatchToProps = createMapDispatchToProps<OwnProps>()({ | |
likePhoto, | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment