1- import * as redux from 'redux'
2-
31import { api } from '../api'
2+
43import * as state from '../reducers/index'
54
65type Q < T > = { request : T }
76type S < T > = { response : T }
87type E = { error : Error }
98
10- type QEmpty = Q < null >
9+ type QEmpty = Q < { } >
1110type QValue = Q < { value : number } >
1211
12+ export interface Dispatch < A > {
13+ ( a : A ) : A
14+ }
15+
16+ type _T = Action [ 'type' ]
17+
18+ type APIActionGroup < TQ extends _T , TS extends _T , TE extends _T , _Q , _S > =
19+ ( { type : TQ } & Q < _Q > )
20+ | ( { type : TS } & Q < _Q > & S < _S > )
21+ | ( { type : TE } & Q < _Q > & E )
22+
23+ type Thunk < Q , S > = ( request : Q ) => Promise < S >
24+
25+ const createThunkAction = < Q , S , TQ extends _T , TS extends _T , TE extends _T >
26+ ( fn : Thunk < Q , S > , tq : TQ , ts : TS , te : TE ) =>
27+ ( request : Q ) =>
28+ ( dispatch : Dispatch < APIActionGroup < TQ , TS , TE , Q , S > > ) => {
29+ dispatch ( { type : tq , request } )
30+ fn ( request )
31+ . then ( response => dispatch ( { type : ts , request, response } ) )
32+ . catch ( error => dispatch ( { type : te , request, error } ) )
33+ }
34+
35+ type LoadAction =
36+ ( { type : 'LOAD_COUNT_REQUEST' } & QEmpty )
37+ | ( { type : 'LOAD_COUNT_SUCCESS' } & QEmpty & S < { value : number } > )
38+ | ( { type : 'LOAD_COUNT_ERROR' } & QEmpty & E )
39+
40+ type SaveAction =
41+ ( { type : 'SAVE_COUNT_REQUEST' } & QValue )
42+ | ( { type : 'SAVE_COUNT_SUCCESS' } & QValue & S < { } > )
43+ | ( { type : 'SAVE_COUNT_ERROR' } & QValue & E )
44+
1345export type Action =
46+ LoadAction
47+ | SaveAction
1448// UI actions
15- { type : 'INCREMENT_COUNTER' , delta : number }
49+ | { type : 'INCREMENT_COUNTER' , delta : number }
1650| { type : 'RESET_COUNTER' }
1751
18- // API Requests
19- | ( { type : 'SAVE_COUNT_REQUEST' } & QValue )
20- | ( { type : 'SAVE_COUNT_SUCCESS' } & QValue & S < { } > )
21- | ( { type : 'SAVE_COUNT_ERROR' } & QValue & E )
52+ export const saveCount = createThunkAction ( api . save ,
53+ 'SAVE_COUNT_REQUEST' ,
54+ 'SAVE_COUNT_SUCCESS' ,
55+ 'SAVE_COUNT_ERROR' )
2256
23- | ( { type : 'LOAD_COUNT_REQUEST' } & QEmpty )
24- | ( { type : 'LOAD_COUNT_SUCCESS' } & QEmpty & S < { value : number } > )
25- | ( { type : 'LOAD_COUNT_ERROR' } & QEmpty & E )
57+ export const loadCount = createThunkAction ( api . load ,
58+ 'LOAD_COUNT_REQUEST' ,
59+ 'LOAD_COUNT_SUCCESS' ,
60+ 'LOAD_COUNT_ERROR' )
2661
2762export const incrementCounter = ( delta : number ) : Action => ( {
2863 type : 'INCREMENT_COUNTER' ,
@@ -32,41 +67,3 @@ export const incrementCounter = (delta: number): Action => ({
3267export const resetCounter = ( ) : Action => ( {
3368 type : 'RESET_COUNTER' ,
3469} )
35-
36- export type ApiActionGroup < _Q , _S > = {
37- request : ( q ?: _Q ) => Action & Q < _Q >
38- success : ( s : _S , q ?: _Q ) => Action & Q < _Q > & S < _S >
39- error : ( e : Error , q ?: _Q ) => Action & Q < _Q > & E
40- }
41-
42- const _saveCount : ApiActionGroup < { value : number } , { } > = {
43- request : ( request ) =>
44- ( { type : 'SAVE_COUNT_REQUEST' , request } ) ,
45- success : ( response , request ) =>
46- ( { type : 'SAVE_COUNT_SUCCESS' , request, response } ) ,
47- error : ( error , request ) =>
48- ( { type : 'SAVE_COUNT_ERROR' , request, error } ) ,
49- }
50-
51- const _loadCount : ApiActionGroup < null , { value : number } > = {
52- request : ( request ) =>
53- ( { type : 'LOAD_COUNT_REQUEST' , request : null } ) ,
54- success : ( response , request ) =>
55- ( { type : 'LOAD_COUNT_SUCCESS' , request : null , response } ) ,
56- error : ( error , request ) =>
57- ( { type : 'LOAD_COUNT_ERROR' , request : null , error } ) ,
58- }
59-
60- type apiFunc < Q , S > = ( q : Q ) => Promise < S >
61-
62- function apiActionGroupFactory < Q , S > ( x : ApiActionGroup < Q , S > , go : apiFunc < Q , S > ) {
63- return ( request : Q ) => ( dispatch : redux . Dispatch < state . All > ) => {
64- dispatch ( x . request ( request ) )
65- go ( request )
66- . then ( ( response ) => dispatch ( x . success ( response , request ) ) )
67- . catch ( ( e : Error ) => dispatch ( x . error ( e , request ) ) )
68- }
69- }
70-
71- export const saveCount = apiActionGroupFactory ( _saveCount , api . save )
72- export const loadCount = ( ) => apiActionGroupFactory ( _loadCount , api . load ) ( null )
0 commit comments