@@ -2,40 +2,64 @@ type Q<T> = { request: T }
22type S<T > = { response: T }
33type E = { error: string }
44
5- type Value = { value :number }
5+ export type Value = { value: number }
66
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+ typeThunkAction< TQ , TS, TE, _Q, _S> =
8+ ({ type:TQ }& Q<_Q >)
9+ | ({ type:TS }& Q<_Q >& S<_S >)
10+ | ({ type:TE }& Q<_Q >& E)
1111
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+ >
1627
1728export type Action =
18- LoadCountAction
19- | SaveCountAction
29+ LoadCount
30+ |SaveCount
2031| { type: 'INCREMENT_COUNTER', delta: number }
2132| { type: 'RESET_COUNTER' }
2233
2334type _T = Action['type']
2435
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 })
2949
3050type Dispatch<A > = (a: A) => A
3151type Thunk<Q , S> = (request: Q) => Promise<S >
3252
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))
3862 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) ))
4165 }