diff --git a/etc/redux-toolkit.api.md b/etc/redux-toolkit.api.md index 700363d48d..a7167b7c3f 100644 --- a/etc/redux-toolkit.api.md +++ b/etc/redux-toolkit.api.md @@ -102,8 +102,13 @@ export function createAction

(type: T): Payl export function createAction, T extends string = string>(type: T, prepareAction: PA): PayloadActionCreator['payload'], T, PA>; // @alpha (undocumented) -export function createAsyncThunk = AsyncThunksArgs>(type: ActionType, payloadCreator: (args: ActionParams, thunkArgs: TA) => Promise | Returned): { - (args: ActionParams): (dispatch: TA["dispatch"], getState: TA["getState"], extra: TA["extra"]) => Promise; +export function createAsyncThunk = AsyncThunksArgs>(type: ActionType, payloadCreator: (args: ActionParams, thunkArgs: TA) => Promise | Returned): ((args: ActionParams) => (dispatch: TA["dispatch"], getState: TA["getState"], extra: TA["extra"]) => Promise | import("./createAction").PayloadAction>) & { pending: import("./createAction").ActionCreatorWithPreparedPayload<[string, ActionParams], undefined, string, never, { args: ActionParams; requestId: string; diff --git a/src/createAsyncThunk.ts b/src/createAsyncThunk.ts index 944b894f25..39713b7e97 100644 --- a/src/createAsyncThunk.ts +++ b/src/createAsyncThunk.ts @@ -101,34 +101,33 @@ export function createAsyncThunk< ) => { const requestId = nanoid() - let result: Returned + let finalAction: ReturnType try { dispatch(pending(requestId, args)) - result = (await payloadCreator(args, { - dispatch, - getState, - extra, - requestId - } as TA)) as Returned + finalAction = fulfilled( + await payloadCreator(args, { + dispatch, + getState, + extra, + requestId + } as TA), + requestId, + args + ) } catch (err) { const serializedError = miniSerializeError(err) - dispatch(rejected(serializedError, requestId, args)) - // Rethrow this so the user can handle if desired - throw err + finalAction = rejected(serializedError, requestId, args) } // We dispatch "success" _after_ the catch, to avoid having any errors // here get swallowed by the try/catch block, // per https://twitter.com/dan_abramov/status/770914221638942720 // and https://redux-toolkit.js.org/tutorials/advanced-tutorial#async-error-handling-logic-in-thunks - return dispatch(fulfilled(result!, requestId, args)) + dispatch(finalAction) + return finalAction } } - actionCreator.pending = pending - actionCreator.rejected = rejected - actionCreator.fulfilled = fulfilled - - return actionCreator + return Object.assign(actionCreator, { pending, rejected, fulfilled }) } diff --git a/type-tests/files/createAsyncThunk.typetest.ts b/type-tests/files/createAsyncThunk.typetest.ts index 8badad5d5d..b50b81f472 100644 --- a/type-tests/files/createAsyncThunk.typetest.ts +++ b/type-tests/files/createAsyncThunk.typetest.ts @@ -1,4 +1,4 @@ -import { createAsyncThunk, Dispatch, createReducer } from 'src' +import { createAsyncThunk, Dispatch, createReducer, AnyAction } from 'src' import { ThunkDispatch } from 'redux-thunk' function expectType(t: T) { @@ -7,20 +7,37 @@ function expectType(t: T) { function fn() {} // basic usage -{ - const dispatch = fn as ThunkDispatch +;(async function() { + const dispatch = fn as ThunkDispatch<{}, any, AnyAction> const async = createAsyncThunk('test', (id: number) => Promise.resolve(id * 2) ) - dispatch(async(3)) const reducer = createReducer({}, builder => builder - .addCase(async.pending, (_, action) => {}) + .addCase(async.pending, (_, action) => { + expectType>(action) + }) .addCase(async.fulfilled, (_, action) => { + expectType>(action) expectType(action.payload) }) - .addCase(async.rejected, (_, action) => {}) + .addCase(async.rejected, (_, action) => { + expectType>(action) + expectType(action.error) + }) ) -} + + const result = await dispatch(async(3)) + + if (async.fulfilled.match(result)) { + expectType>(result) + // typings:expect-error + expectType>(result) + } else { + expectType>(result) + // typings:expect-error + expectType>(result) + } +})()