Skip to content

Commit 67718f4

Browse files
committed
Tags types
1 parent f955226 commit 67718f4

File tree

2 files changed

+60
-31
lines changed

2 files changed

+60
-31
lines changed

src/actions/action.ts

Lines changed: 46 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,40 +2,64 @@ type Q<T> = { request: T }
22
type S<T> = { response: T }
33
type 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+
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)
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

1728
export type Action =
18-
LoadCountAction
19-
| SaveCountAction
29+
LoadCount
30+
| SaveCount
2031
| { type: 'INCREMENT_COUNTER', delta: number }
2132
| { type: 'RESET_COUNTER' }
2233

2334
type _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

3050
type Dispatch<A> = (a: A) => A
3151
type 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
}

src/actions/index.ts

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@ import { api } from '../api'
22

33
import {
44
Action,
5-
createThunkAction,
5+
LoadCount,
6+
SaveCount,
7+
dispatcher,
8+
asReq,
9+
asRes,
10+
asErr,
611
} from './action'
712

813
export { Action }
@@ -16,12 +21,12 @@ export const resetCounter = (): Action => ({
1621
type: 'RESET_COUNTER',
1722
})
1823

19-
export const saveCount = createThunkAction(api.save,
20-
'SAVE_COUNT_REQUEST',
21-
'SAVE_COUNT_SUCCESS',
22-
'SAVE_COUNT_ERROR')
24+
export const loadCount = dispatcher(api.load)<LoadCount>(
25+
asReq('LOAD_COUNT_REQUEST'),
26+
asRes('LOAD_COUNT_SUCCESS'),
27+
asErr('LOAD_COUNT_ERROR'))
2328

24-
export const loadCount = createThunkAction(api.load,
25-
'LOAD_COUNT_REQUEST',
26-
'LOAD_COUNT_SUCCESS',
27-
'LOAD_COUNT_ERROR')
29+
export const saveCount = dispatcher(api.save)<SaveCount>(
30+
asReq('SAVE_COUNT_REQUEST'),
31+
asRes('SAVE_COUNT_SUCCESS'),
32+
asErr('SAVE_COUNT_ERROR'))

0 commit comments

Comments
 (0)