@@ -2,40 +2,64 @@ type Q<T> = { request: T }
2
2
type S<T > = { response: T }
3
3
type E = { error: string }
4
4
5
- type Value = { value : number }
5
+ export type Value = { value: number }
6
6
7
- type LoadCountAction =
8
- ( { type : 'LOAD_COUNT_REQUEST' } & Q < { } > )
9
- | ( { type : 'LOAD_COUNT_SUCCESS' } & Q < { } > & S < Value > )
10
- | ( { type : 'LOAD_COUNT_ERROR' } & Q < { } > & E )
7
+ type ThunkAction< TQ , TS, TE, _Q, _S> =
8
+ ({ type: TQ } & Q<_Q >)
9
+ | ({ type: TS } & Q<_Q > & S<_S >)
10
+ | ({ type: TE } & Q<_Q > & E)
11
11
12
- type SaveCountAction =
13
- ( { type : 'SAVE_COUNT_REQUEST' } & Q < Value > )
14
- | ( { type : 'SAVE_COUNT_SUCCESS' } & Q < Value > & S < { } > )
15
- | ( { type : 'SAVE_COUNT_ERROR' } & Q < Value > & E )
12
+ export type LoadCount = ThunkAction<
13
+ 'LOAD_COUNT_REQUEST',
14
+ 'LOAD_COUNT_SUCCESS',
15
+ 'LOAD_COUNT_ERROR',
16
+ {},
17
+ Value
18
+ >
19
+
20
+ export type SaveCount = ThunkAction<
21
+ 'SAVE_COUNT_REQUEST',
22
+ 'SAVE_COUNT_SUCCESS',
23
+ 'SAVE_COUNT_ERROR',
24
+ Value,
25
+ {}
26
+ >
16
27
17
28
export type Action =
18
- LoadCountAction
19
- | SaveCountAction
29
+ LoadCount
30
+ | SaveCount
20
31
| { type: 'INCREMENT_COUNTER', delta: number }
21
32
| { type: 'RESET_COUNTER' }
22
33
23
34
type _T = Action['type']
24
35
25
- type ThunkActionGroup < TQ extends _T , TS extends _T , TE extends _T , _Q , _S > =
26
- ( { type : TQ } & Q < _Q > )
27
- | ( { type : TS } & Q < _Q > & S < _S > )
28
- | ( { type : TE } & Q < _Q > & E )
36
+ // TypeScript won't narrow a `ThunkAction` union directly, but
37
+ // we can help it out by tagging the three permutations.
38
+ export const asReq = <TQ extends _T>(type: TQ) =>
39
+ <_Q >(request: _Q) =>
40
+ ({ type, request })
41
+
42
+ export const asRes = <TS extends _T>(type: TS) =>
43
+ <_Q , _S>(request: _Q, response: _S) =>
44
+ ({ type, request, response })
45
+
46
+ export const asErr = <TE extends _T>(type: TE) =>
47
+ <_Q >(request: _Q, error: string) =>
48
+ ({ type, request, error })
29
49
30
50
type Dispatch<A > = (a: A) => A
31
51
type Thunk<Q , S> = (request: Q) => Promise<S >
32
52
33
- export const createThunkAction = < Q , S , TQ extends _T , TS extends _T , TE extends _T >
34
- ( fn : Thunk < Q , S > , tq : TQ , ts : TS , te : TE ) =>
35
- ( request : Q ) =>
36
- ( dispatch : Dispatch < ThunkActionGroup < TQ , TS , TE , Q , S > > ) => {
37
- dispatch ( { type : tq , request } )
53
+ type ReqCreator<A , _Q> = (q: _Q) => A
54
+ type ResCreator<A , _Q, _S> = (q: _Q, s: _S) => A
55
+ type ErrCreator<A , _Q> = (q: _Q, e: string) => A
56
+
57
+ export const dispatcher = <_Q , _S>(fn: Thunk<_Q , _S>) =>
58
+ <A extends Action>(tq: ReqCreator<A , _Q>, ts: ResCreator<A , _Q, _S>, te: ErrCreator<A , _Q>) =>
59
+ (request: _Q) =>
60
+ (dispatch: Dispatch<A >) => {
61
+ dispatch(tq(request))
38
62
fn(request)
39
- . then ( response => dispatch ( { type : ts , request, response } ) )
40
- . catch ( err => dispatch ( { type : te , request, error : err . message } ) )
63
+ .then(response => dispatch(ts( request, response) ))
64
+ .catch(err => dispatch(te( request, err.message) ))
41
65
}
0 commit comments