Skip to content

Commit 4940605

Browse files
committed
typings experiment
1 parent 2774dd7 commit 4940605

File tree

2 files changed

+49
-34
lines changed

2 files changed

+49
-34
lines changed

src/createAsyncThunk.ts

Lines changed: 22 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,12 @@
11
import { Dispatch } from 'redux'
22
import { createAction } from './createAction'
33

4-
export type Await<T> = T extends {
5-
then(onfulfilled?: (value: infer U) => unknown): unknown
6-
}
7-
? U
8-
: T
9-
10-
export interface AsyncThunkParams<
11-
A,
12-
D extends Dispatch,
13-
S extends unknown,
14-
E extends unknown
15-
> {
16-
args: A
4+
type AsyncThunksArgs<S, E, D extends Dispatch = Dispatch> = {
175
dispatch: D
18-
getState: () => S
6+
getState: S
197
extra: E
208
}
219

22-
export type AsyncActionCreator<
23-
A,
24-
D extends Dispatch,
25-
S extends unknown,
26-
E extends unknown
27-
> = (params: AsyncThunkParams<A, D, S, E>) => any
28-
2910
/**
3011
*
3112
* @param type
@@ -35,19 +16,23 @@ export type AsyncActionCreator<
3516
*/
3617
export function createAsyncThunk<
3718
ActionType extends string,
38-
PayloadCreator extends AsyncActionCreator<
19+
Returned,
20+
ActionParams = never,
21+
TA extends AsyncThunksArgs<any, any, any> = AsyncThunksArgs<
3922
unknown,
40-
Dispatch,
4123
unknown,
42-
undefined
24+
Dispatch
4325
>
44-
>(type: ActionType, payloadCreator: PayloadCreator) {
45-
// TODO This results in some hideous-looking inferred types for the actions
46-
type ActionParams = Parameters<PayloadCreator>[0]['args']
47-
26+
>(
27+
type: ActionType,
28+
payloadCreator: (
29+
args: ActionParams,
30+
thunkArgs: TA
31+
) => Promise<Returned> | Returned
32+
) {
4833
const fulfilled = createAction(
4934
type + '/fulfilled',
50-
(result: Await<ReturnType<PayloadCreator>>, args: ActionParams) => {
35+
(result: Returned, args: ActionParams) => {
5136
return {
5237
payload: result,
5338
meta: { args }
@@ -80,17 +65,20 @@ export function createAsyncThunk<
8065
}
8166
)
8267

83-
function actionCreator(args?: ActionParams) {
84-
return async (dispatch: any, getState: any, extra: any) => {
68+
function actionCreator(args: ActionParams) {
69+
return async (
70+
dispatch: TA['dispatch'],
71+
getState: TA['getState'],
72+
extra: TA['extra']
73+
) => {
8574
try {
8675
dispatch(pending(args))
8776
// TODO Also ugly types
88-
const result: Await<ReturnType<PayloadCreator>> = await payloadCreator({
89-
args,
77+
const result = (await payloadCreator(args, {
9078
dispatch,
9179
getState,
9280
extra
93-
})
81+
} as TA)) as Returned
9482

9583
// TODO How do we avoid errors in here from hitting the catch clause?
9684
return dispatch(fulfilled(result, args))
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { createAsyncThunk, Dispatch, createReducer } from 'src'
2+
import { ThunkDispatch } from 'redux-thunk'
3+
4+
function expectType<T>(t: T) {
5+
return t
6+
}
7+
function fn() {}
8+
9+
// basic usage
10+
{
11+
const dispatch = fn as ThunkDispatch<any, any, any>
12+
13+
const async = createAsyncThunk('test', (id: number) =>
14+
Promise.resolve(id * 2)
15+
)
16+
dispatch(async(3))
17+
18+
const reducer = createReducer({}, builder =>
19+
builder
20+
.addCase(async.pending, (_, action) => {})
21+
.addCase(async.fulfilled, (_, action) => {
22+
expectType<number>(action.payload)
23+
})
24+
.addCase(async.rejected, (_, action) => {})
25+
.addCase(async.finished, (_, action) => {})
26+
)
27+
}

0 commit comments

Comments
 (0)