diff --git a/README.md b/README.md index 3064401..ccfa277 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,7 @@ This gives you the power to prioritize our work and support the project contribu - [Store Configuration](#store-configuration) 📝 __UPDATED__ - [Async Flow](#async-flow) 📝 __UPDATED__ - [Selectors](#selectors) + - [Typing connect](#typing-connect) 🌟 __NEW__ - [Tools](#tools) - [TSLint](#tslint) - [Jest](#jest) @@ -637,7 +638,7 @@ A decent alternative I can recommend is to use `() => any` type, it will work ju > There is alternative way to retain type soundness but it requires an explicit wrapping with `dispatch` and will be very tedious for the long run. See example below: ``` -const mapDispatchToProps = (dispatch: Dispatch) => ({ +const mapDispatchToProps = (dispatch: Dispatch) => ({ onIncrement: () => dispatch(actions.increment()), }); ``` @@ -692,7 +693,7 @@ const mapStateToProps = (state: Types.RootState) => ({ count: state.counters.reduxCounter, }); -const mapDispatchToProps = (dispatch: Dispatch) => bindActionCreators({ +const mapDispatchToProps = (dispatch: Dispatch) => bindActionCreators({ onIncrement: countersActions.increment, }, dispatch); @@ -1110,6 +1111,41 @@ export const getFilteredTodos = createSelector(getTodos, getTodosFilter, (todos, --- +## Typing connect + +Below snippet can be find in the `playground/` folder, you can checkout the repo and follow all dependencies to understand the bigger picture. +`playground/src/connected/sfc-counter-connected-verbose.tsx` + +```tsx +import Types from 'Types'; + +import { bindActionCreators, Dispatch } from 'redux'; +import { connect } from 'react-redux'; + +import { countersActions } from '../features/counters'; +import { SFCCounter, SFCCounterProps } from '../components'; + +// `state` parameter needs a type annotation to type-check the correct shape of a state object but also it'll be used by "type inference" to infer the type of returned props +const mapStateToProps = (state: Types.RootState, ownProps: SFCCounterProps) => ({ + count: state.counters.reduxCounter, +}); + +// `dispatch` parameter needs a type annotation to type-check the correct shape of an action object when using dispatch function +const mapDispatchToProps = (dispatch: Dispatch) => bindActionCreators({ + onIncrement: countersActions.increment, + // without using action creators, this will be validated using your RootAction union type + // onIncrement: () => dispatch({ type: "counters/INCREMENT" }), +}, dispatch); + +// NOTE: We don't need to pass generic type arguments to neither connect nor mapping functions because type inference will do all this work automatically. So there's really no reason to increase the noise ratio in your codebase! +export const SFCCounterConnectedVerbose = + connect(mapStateToProps, mapDispatchToProps)(SFCCounter); +``` + +[⇧ back to top](#table-of-contents) + +--- + # Tools ## TSLint diff --git a/docs/markdown/1_react.md b/docs/markdown/1_react.md index 7779dcf..393a241 100644 --- a/docs/markdown/1_react.md +++ b/docs/markdown/1_react.md @@ -177,7 +177,7 @@ A decent alternative I can recommend is to use `() => any` type, it will work ju > There is alternative way to retain type soundness but it requires an explicit wrapping with `dispatch` and will be very tedious for the long run. See example below: ``` -const mapDispatchToProps = (dispatch: Dispatch) => ({ +const mapDispatchToProps = (dispatch: Dispatch) => ({ onIncrement: () => dispatch(actions.increment()), }); ``` diff --git a/docs/markdown/2_redux.md b/docs/markdown/2_redux.md index ec506fe..7e05c70 100644 --- a/docs/markdown/2_redux.md +++ b/docs/markdown/2_redux.md @@ -138,3 +138,38 @@ When creating a store instance we don't need to provide any additional types. It ::example='../../playground/src/features/todos/selectors.ts':: [⇧ back to top](#table-of-contents) + +--- + +## Typing connect + +Below snippet can be find in the `playground/` folder, you can checkout the repo and follow all dependencies to understand the bigger picture. +`playground/src/connected/sfc-counter-connected-verbose.tsx` + +```tsx +import Types from 'Types'; + +import { bindActionCreators, Dispatch } from 'redux'; +import { connect } from 'react-redux'; + +import { countersActions } from '../features/counters'; +import { SFCCounter, SFCCounterProps } from '../components'; + +// `state` parameter needs a type annotation to type-check the correct shape of a state object but also it'll be used by "type inference" to infer the type of returned props +const mapStateToProps = (state: Types.RootState, ownProps: SFCCounterProps) => ({ + count: state.counters.reduxCounter, +}); + +// `dispatch` parameter needs a type annotation to type-check the correct shape of an action object when using dispatch function +const mapDispatchToProps = (dispatch: Dispatch) => bindActionCreators({ + onIncrement: countersActions.increment, + // without using action creators, this will be validated using your RootAction union type + // onIncrement: () => dispatch({ type: "counters/INCREMENT" }), +}, dispatch); + +// NOTE: We don't need to pass generic type arguments to neither connect nor mapping functions because type inference will do all this work automatically. So there's really no reason to increase the noise ratio in your codebase! +export const SFCCounterConnectedVerbose = + connect(mapStateToProps, mapDispatchToProps)(SFCCounter); +``` + +[⇧ back to top](#table-of-contents) diff --git a/docs/markdown/_toc.md b/docs/markdown/_toc.md index 05df687..54f0d5b 100644 --- a/docs/markdown/_toc.md +++ b/docs/markdown/_toc.md @@ -17,6 +17,7 @@ - [Store Configuration](#store-configuration) 📝 __UPDATED__ - [Async Flow](#async-flow) 📝 __UPDATED__ - [Selectors](#selectors) + - [Typing connect](#typing-connect) 🌟 __NEW__ - [Tools](#tools) - [TSLint](#tslint) - [Jest](#jest) diff --git a/playground/src/connected/sfc-counter-connected-verbose.tsx b/playground/src/connected/sfc-counter-connected-verbose.tsx index 4d980dd..dfc9b55 100644 --- a/playground/src/connected/sfc-counter-connected-verbose.tsx +++ b/playground/src/connected/sfc-counter-connected-verbose.tsx @@ -9,7 +9,7 @@ const mapStateToProps = (state: Types.RootState) => ({ count: state.counters.reduxCounter, }); -const mapDispatchToProps = (dispatch: Dispatch) => bindActionCreators({ +const mapDispatchToProps = (dispatch: Dispatch) => bindActionCreators({ onIncrement: countersActions.increment, }, dispatch);