From 8909f104e8d88ca5679f7eac97d5b379aa83aa1c Mon Sep 17 00:00:00 2001 From: Lenz Weber Date: Wed, 9 Nov 2022 07:16:24 +0000 Subject: [PATCH 1/2] fulfillWithValue should infer return value --- packages/toolkit/src/createAsyncThunk.ts | 41 ++++++++--------- .../src/tests/createAsyncThunk.typetest.ts | 44 ++++++++++++++++--- 2 files changed, 56 insertions(+), 29 deletions(-) diff --git a/packages/toolkit/src/createAsyncThunk.ts b/packages/toolkit/src/createAsyncThunk.ts index f3361b699..75c0c4925 100644 --- a/packages/toolkit/src/createAsyncThunk.ts +++ b/packages/toolkit/src/createAsyncThunk.ts @@ -405,16 +405,18 @@ export type AsyncThunk< Returned, ThunkArg, ThunkApiConfig extends AsyncThunkConfig -> = AsyncThunkActionCreator & { - pending: AsyncThunkPendingActionCreator - rejected: AsyncThunkRejectedActionCreator - fulfilled: AsyncThunkFulfilledActionCreator< - Returned, - ThunkArg, - ThunkApiConfig - > - typePrefix: string -} +> = [Returned] extends [FulfillWithMeta] + ? AsyncThunk + : AsyncThunkActionCreator & { + pending: AsyncThunkPendingActionCreator + rejected: AsyncThunkRejectedActionCreator + fulfilled: AsyncThunkFulfilledActionCreator< + Returned, + ThunkArg, + ThunkApiConfig + > + typePrefix: string + } type OverrideThunkApiConfigs = Id< NewConfig & Omit @@ -694,19 +696,12 @@ If you want to use the AbortController to react to \`abort\` events, please cons } } - return Object.assign( - actionCreator as AsyncThunkActionCreator< - Returned, - ThunkArg, - ThunkApiConfig - >, - { - pending, - rejected, - fulfilled, - typePrefix, - } - ) + return Object.assign(actionCreator as any, { + pending, + rejected, + fulfilled, + typePrefix, + }) } createAsyncThunk.withTypes = () => createAsyncThunk diff --git a/packages/toolkit/src/tests/createAsyncThunk.typetest.ts b/packages/toolkit/src/tests/createAsyncThunk.typetest.ts index 369b6b34a..2bfc8c058 100644 --- a/packages/toolkit/src/tests/createAsyncThunk.typetest.ts +++ b/packages/toolkit/src/tests/createAsyncThunk.typetest.ts @@ -525,6 +525,38 @@ const anyAction = { type: 'foo' } as AnyAction }) } +{ + // https://github.com/reduxjs/redux-toolkit/issues/2886 + // fulfillWithValue should infer return value + + const initialState = { + loading: false, + obj: { magic: '' }, + } + + const getObj = createAsyncThunk( + 'slice/getObj', + async (_: any, { fulfillWithValue, rejectWithValue }) => { + try { + return fulfillWithValue({ magic: 'object' }) + } catch (rejected: any) { + return rejectWithValue(rejected?.response?.error || rejected) + } + } + ) + + createSlice({ + name: 'slice', + initialState, + reducers: {}, + extraReducers: (builder) => { + builder.addCase(getObj.fulfilled, (state, action) => { + expectExactType<{ magic: string }>(ANY)(action.payload) + }) + }, + }) +} + // meta return values { // return values @@ -621,8 +653,8 @@ const anyAction = { type: 'foo' } as AnyAction // correct extra type const { s, n } = api.extra - expectExactType(s) - expectExactType(n) + expectExactType(ANY)(s) + expectExactType(ANY)(n) if (1 < 2) // @ts-expect-error @@ -646,8 +678,8 @@ const anyAction = { type: 'foo' } as AnyAction }) // correct extra type const { s, n } = api.extra - expectExactType(s) - expectExactType(n) + expectExactType(ANY)(s) + expectExactType(ANY)(n) if (1 < 2) // @ts-expect-error @@ -673,8 +705,8 @@ const anyAction = { type: 'foo' } as AnyAction }) // correct extra type const { s, n } = api.extra - expectExactType(s) - expectExactType(n) + expectExactType(ANY)(s) + expectExactType(ANY)(n) if (1 < 2) return api.rejectWithValue(5) if (1 < 2) // @ts-expect-error From 73cd6031306d531ddf0af7e7a4383c43912eafa6 Mon Sep 17 00:00:00 2001 From: Lenz Weber Date: Thu, 10 Nov 2022 07:31:28 +0000 Subject: [PATCH 2/2] revert changes, just change return type of single-argument `fulfillWithValue` signature --- packages/toolkit/src/createAsyncThunk.ts | 45 +++++++++++++----------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/packages/toolkit/src/createAsyncThunk.ts b/packages/toolkit/src/createAsyncThunk.ts index 75c0c4925..58df87bb9 100644 --- a/packages/toolkit/src/createAsyncThunk.ts +++ b/packages/toolkit/src/createAsyncThunk.ts @@ -35,9 +35,7 @@ export type BaseThunkAPI< > fulfillWithValue: IsUnknown< FulfilledMeta, - ( - value: FulfilledValue - ) => FulfillWithMeta, + (value: FulfilledValue) => FulfilledValue, ( value: FulfilledValue, meta: FulfilledMeta @@ -405,18 +403,16 @@ export type AsyncThunk< Returned, ThunkArg, ThunkApiConfig extends AsyncThunkConfig -> = [Returned] extends [FulfillWithMeta] - ? AsyncThunk - : AsyncThunkActionCreator & { - pending: AsyncThunkPendingActionCreator - rejected: AsyncThunkRejectedActionCreator - fulfilled: AsyncThunkFulfilledActionCreator< - Returned, - ThunkArg, - ThunkApiConfig - > - typePrefix: string - } +> = AsyncThunkActionCreator & { + pending: AsyncThunkPendingActionCreator + rejected: AsyncThunkRejectedActionCreator + fulfilled: AsyncThunkFulfilledActionCreator< + Returned, + ThunkArg, + ThunkApiConfig + > + typePrefix: string +} type OverrideThunkApiConfigs = Id< NewConfig & Omit @@ -696,12 +692,19 @@ If you want to use the AbortController to react to \`abort\` events, please cons } } - return Object.assign(actionCreator as any, { - pending, - rejected, - fulfilled, - typePrefix, - }) + return Object.assign( + actionCreator as AsyncThunkActionCreator< + Returned, + ThunkArg, + ThunkApiConfig + >, + { + pending, + rejected, + fulfilled, + typePrefix, + } + ) } createAsyncThunk.withTypes = () => createAsyncThunk