Skip to content

Instantly share code, notes, and snippets.

@OliverJAsh
Created November 2, 2018 11:04
Show Gist options
  • Save OliverJAsh/fd210d846aaf4e941346f384b6aa7ba6 to your computer and use it in GitHub Desktop.
Save OliverJAsh/fd210d846aaf4e941346f384b6aa7ba6 to your computer and use it in GitHub Desktop.
React Redux: infer Redux props from mappers
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