@@ -251,44 +251,43 @@ interface State {
251
251
count: number ;
252
252
}
253
253
254
- export class StatefulCounterWithDefault extends React .Component <StatefulCounterWithDefaultProps , State > {
255
- // to make defaultProps strictly typed we need to explicitly declare their type
256
- // @see https://github.com/DefinitelyTyped/DefinitelyTyped/issues/11640
257
- static defaultProps: DefaultProps = {
258
- initialCount: 0 ,
259
- };
260
-
261
- props: StatefulCounterWithDefaultProps & DefaultProps ;
254
+ export const StatefulCounterWithDefault: React .ComponentClass <StatefulCounterWithDefaultProps > =
255
+ class extends React .Component <StatefulCounterWithDefaultProps & DefaultProps > {
256
+ // to make defaultProps strictly typed we need to explicitly declare their type
257
+ // @see https://github.com/DefinitelyTyped/DefinitelyTyped/issues/11640
258
+ static defaultProps: DefaultProps = {
259
+ initialCount: 0 ,
260
+ };
262
261
263
- state: State = {
264
- count: this .props .initialCount ,
265
- };
262
+ state: State = {
263
+ count: this .props .initialCount ,
264
+ };
266
265
267
- componentWillReceiveProps({ initialCount }: StatefulCounterWithDefaultProps ) {
268
- if (initialCount != null && initialCount !== this .props .initialCount ) {
269
- this .setState ({ count: initialCount });
266
+ componentWillReceiveProps({ initialCount }: StatefulCounterWithDefaultProps ) {
267
+ if (initialCount != null && initialCount !== this .props .initialCount ) {
268
+ this .setState ({ count: initialCount });
269
+ }
270
270
}
271
- }
272
271
273
- handleIncrement = () => {
274
- this .setState ({ count: this .state .count + 1 });
275
- }
272
+ handleIncrement = () => {
273
+ this .setState ({ count: this .state .count + 1 });
274
+ }
276
275
277
- render() {
278
- const { handleIncrement } = this ;
279
- const { label } = this .props ;
280
- const { count } = this .state ;
276
+ render() {
277
+ const { handleIncrement } = this ;
278
+ const { label } = this .props ;
279
+ const { count } = this .state ;
281
280
282
- return (
283
- <div >
284
- <span >{ label } : { count } </span >
285
- <button type = " button" onClick = { handleIncrement } >
286
- { ` Increment ` }
287
- </button >
288
- </div >
289
- );
290
- }
291
- }
281
+ return (
282
+ <div >
283
+ <span >{ label } : { count } </span >
284
+ <button type = " button" onClick = { handleIncrement } >
285
+ { ` Increment ` }
286
+ </button >
287
+ </div >
288
+ );
289
+ }
290
+ };
292
291
293
292
` ` `
294
293
@@ -342,7 +341,7 @@ Adds state to a stateless counter
342
341
343
342
` ` ` tsx
344
343
import * as React from ' react' ;
345
- import { Diff as Subtract } from ' react-redux-typescript ' ;
344
+ import { Subtract } from ' utility-types ' ;
346
345
347
346
// These props will be subtracted from original component type
348
347
interface WrappedComponentProps {
@@ -414,7 +413,7 @@ Adds error handling using componentDidCatch to any component
414
413
415
414
` ` ` tsx
416
415
import * as React from ' react' ;
417
- import { Diff as Subtract } from ' react-redux-typescript ' ;
416
+ import { Subtract } from ' utility-types ' ;
418
417
419
418
const MISSING_ERROR = ' Error was swallowed during propagation.' ;
420
419
@@ -521,15 +520,15 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({
521
520
import { connect } from ' react-redux' ;
522
521
523
522
import { RootState } from ' @src/redux' ;
524
- import { actions , CountersSelectors } from ' @src/redux/counters' ;
523
+ import { countersActions , CountersSelectors } from ' @src/redux/counters' ;
525
524
import { SFCCounter } from ' @src/components' ;
526
525
527
526
const mapStateToProps = (state : RootState ) => ({
528
527
count: CountersSelectors .getReduxCounter (state ),
529
528
});
530
529
531
530
export const SFCCounterConnected = connect (mapStateToProps , {
532
- onIncrement: actions .increment ,
531
+ onIncrement: countersActions .increment ,
533
532
})(SFCCounter );
534
533
535
534
` ` `
@@ -558,15 +557,15 @@ import { bindActionCreators } from 'redux';
558
557
import { connect } from ' react-redux' ;
559
558
560
559
import { RootState , Dispatch } from ' @src/redux' ;
561
- import { actions } from ' @src/redux/counters' ;
560
+ import { countersActions } from ' @src/redux/counters' ;
562
561
import { SFCCounter } from ' @src/components' ;
563
562
564
563
const mapStateToProps = (state : RootState ) => ({
565
564
count: state .counters .reduxCounter ,
566
565
});
567
566
568
567
const mapDispatchToProps = (dispatch : Dispatch ) => bindActionCreators ({
569
- onIncrement: actions .increment ,
568
+ onIncrement: countersActions .increment ,
570
569
}, dispatch );
571
570
572
571
export const SFCCounterConnectedVerbose =
@@ -597,7 +596,7 @@ export default () => (
597
596
import { connect } from ' react-redux' ;
598
597
599
598
import { RootState } from ' @src/redux' ;
600
- import { actions , CountersSelectors } from ' @src/redux/counters' ;
599
+ import { countersActions , CountersSelectors } from ' @src/redux/counters' ;
601
600
import { SFCCounter } from ' @src/components' ;
602
601
603
602
export interface SFCCounterConnectedExtended {
@@ -609,7 +608,7 @@ const mapStateToProps = (state: RootState, ownProps: SFCCounterConnectedExtended
609
608
});
610
609
611
610
export const SFCCounterConnectedExtended = connect (mapStateToProps , {
612
- onIncrement: actions .increment ,
611
+ onIncrement: countersActions .increment ,
613
612
})(SFCCounter );
614
613
615
614
` ` `
@@ -647,7 +646,7 @@ All that without losing type-safety! Please check this very short [Tutorial](htt
647
646
` ` ` tsx
648
647
import { createAction } from ' typesafe-actions' ;
649
648
650
- export const actions = {
649
+ export const countersActions = {
651
650
increment: createAction (' INCREMENT' ),
652
651
add: createAction (' ADD' , (amount : number ) => ({
653
652
type: ' ADD' ,
@@ -660,10 +659,10 @@ export const actions = {
660
659
661
660
` ` ` tsx
662
661
import store from ' @src/store' ;
663
- import { actions } from ' @src/redux/counters' ;
662
+ import { countersActions } from ' @src/redux/counters' ;
664
663
665
664
// store.dispatch(actionCreators.increment(1)); // Error: Expected 0 arguments, but got 1.
666
- store .dispatch (actions .increment ()); // OK => { type: "INCREMENT" }
665
+ store .dispatch (countersActions .increment ()); // OK => { type: "INCREMENT" }
667
666
668
667
` ` `
669
668
</p></details>
@@ -738,7 +737,7 @@ import { getType } from 'typesafe-actions';
738
737
739
738
import { RootAction } from ' @src/redux' ;
740
739
741
- import { actions } from ' ./' ;
740
+ import { countersActions } from ' ./' ;
742
741
743
742
export type State = {
744
743
readonly reduxCounter: number ;
@@ -747,11 +746,11 @@ export type State = {
747
746
export const reducer = combineReducers <State , RootAction >({
748
747
reduxCounter : (state = 0 , action ) => {
749
748
switch (action .type ) {
750
- case getType (actions .increment ):
751
- return state + 1 ;
749
+ case getType (countersActions .increment ):
750
+ return state + 1 ; // action is type: { type: "INCREMENT"; }
752
751
753
- case getType (actions .add ):
754
- return state + action .payload ;
752
+ case getType (countersActions .add ):
753
+ return state + action .payload ; // action is type: { type: "ADD"; payload: number; }
755
754
756
755
default :
757
756
return state ;
@@ -804,21 +803,19 @@ Can be imported in various layers receiving or sending redux actions like: reduc
804
803
` ` ` tsx
805
804
// RootActions
806
805
import { RouterAction , LocationChangeAction } from ' react-router-redux' ;
807
- import { getReturnOfExpression } from ' react-redux-typescript ' ;
806
+ import { $call } from ' utility-types ' ;
808
807
809
- import { actions as countersAC } from ' @src/redux/counters' ;
810
- import { actions as todosAC } from ' @src/redux/todos' ;
811
- import { actions as toastsAC } from ' @src/redux/toasts' ;
808
+ import { countersActions } from ' @src/redux/counters' ;
809
+ import { todosActions } from ' @src/redux/todos' ;
810
+ import { toastsActions } from ' @src/redux/toasts' ;
812
811
813
- export const allActions = {
814
- ... countersAC ,
815
- ... todosAC ,
816
- ... toastsAC ,
817
- } ;
812
+ const returnsOfActions = [
813
+ ... Object . values ( countersActions ) ,
814
+ ... Object . values ( todosActions ) ,
815
+ ... Object . values ( toastsActions ) ,
816
+ ]. map ( $call ) ;
818
817
819
- const returnOfActions =
820
- Object .values (allActions ).map (getReturnOfExpression );
821
- type AppAction = typeof returnOfActions [number ];
818
+ type AppAction = typeof returnsOfActions [number ];
822
819
type ReactRouterAction = RouterAction | LocationChangeAction ;
823
820
824
821
export type RootAction =
@@ -875,25 +872,28 @@ export default store;
875
872
876
873
### "redux-observable"
877
874
875
+ Use ` isActionOf ` helper to filter actions and to narrow ` RootAction ` union type to a specific "action type" down the stream.
876
+
878
877
` ` ` tsx
879
878
import { combineEpics , Epic } from ' redux-observable' ;
880
879
import { isActionOf } from ' typesafe-actions' ;
881
880
import { Observable } from ' rxjs/Observable' ;
882
881
import { v4 } from ' uuid' ;
883
882
884
- import { RootAction , RootState , allActions } from ' @src/redux' ;
885
- import { actions } from ' ./' ;
883
+ import { RootAction , RootState } from ' @src/redux' ;
884
+ import { todosActions } from ' @src/redux/todos' ;
885
+ import { toastsActions } from ' ./' ;
886
886
887
887
const TOAST_LIFETIME = 2000 ;
888
888
889
889
const addTodoToast: Epic <RootAction , RootState > =
890
890
(action$ , store ) => action$
891
- .filter (isActionOf (allActions .addTodo ))
892
- .concatMap ((action ) => {
891
+ .filter (isActionOf (todosActions .addTodo ))
892
+ .concatMap ((action ) => { // action is type: { type: "ADD_TODO"; payload: string; }
893
893
const toast = { id: v4 (), text: action .payload };
894
894
895
- const addToast$ = Observable .of (actions .addToast (toast ));
896
- const removeToast$ = Observable .of (actions .removeToast (toast .id ))
895
+ const addToast$ = Observable .of (toastsActions .addToast (toast ));
896
+ const removeToast$ = Observable .of (toastsActions .removeToast (toast .id ))
897
897
.delay (TOAST_LIFETIME );
898
898
899
899
return addToast$ .concat (removeToast$ );
@@ -965,7 +965,9 @@ export type Actions = {
965
965
type: typeof ADD ,
966
966
payload: number ,
967
967
},
968
- };
968
+ };
969
+
970
+ export type RootAction = Actions [keyof Actions ];
969
971
970
972
export const actions = {
971
973
increment : (): Actions [typeof INCREMENT ] => ({
@@ -979,6 +981,7 @@ export const actions = {
979
981
` ` `
980
982
981
983
[⇧ back to top](#table-of-contents)
984
+
982
985
---
983
986
984
987
# Tools
@@ -1307,7 +1310,6 @@ node ./generator/bin/generate-readme.js
1307
1310
1308
1311
# Project Examples
1309
1312
1310
- https://github.com/piotrwitek/react-redux-typescript-starter-kit
1311
1313
https://github.com/piotrwitek/react-redux-typescript-webpack-starter
1312
1314
1313
1315
[⇧ back to top](#table-of-contents)
0 commit comments