Skip to content

Commit ece8442

Browse files
committed
split asyncThunkCreator into its own file
1 parent 930e868 commit ece8442

File tree

5 files changed

+476
-453
lines changed

5 files changed

+476
-453
lines changed
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
import type {
2+
AsyncThunk,
3+
AsyncThunkConfig,
4+
AsyncThunkOptions,
5+
AsyncThunkPayloadCreator,
6+
OverrideThunkApiConfigs,
7+
} from './createAsyncThunk'
8+
import { createAsyncThunk } from './createAsyncThunk'
9+
import type { CaseReducer } from './createReducer'
10+
import type {
11+
CreatorCaseReducers,
12+
ReducerCreator,
13+
ReducerCreatorEntry,
14+
ReducerDefinition,
15+
ReducerNamesOfType,
16+
} from './createSlice'
17+
import { ReducerType } from './createSlice'
18+
import type { Id } from './tsHelpers'
19+
20+
declare module '@reduxjs/toolkit' {
21+
export interface SliceReducerCreators<
22+
State,
23+
CaseReducers extends CreatorCaseReducers<State>,
24+
Name extends string = string,
25+
> {
26+
[ReducerType.asyncThunk]: ReducerCreatorEntry<
27+
AsyncThunkCreator<State>,
28+
{
29+
actions: {
30+
[ReducerName in ReducerNamesOfType<
31+
CaseReducers,
32+
ReducerType.asyncThunk
33+
>]: CaseReducers[ReducerName] extends AsyncThunkSliceReducerDefinition<
34+
State,
35+
infer ThunkArg,
36+
infer Returned,
37+
infer ThunkApiConfig
38+
>
39+
? AsyncThunk<Returned, ThunkArg, ThunkApiConfig>
40+
: never
41+
}
42+
caseReducers: {
43+
[ReducerName in ReducerNamesOfType<
44+
CaseReducers,
45+
ReducerType.asyncThunk
46+
>]: CaseReducers[ReducerName] extends AsyncThunkSliceReducerDefinition<
47+
State,
48+
any,
49+
any,
50+
any
51+
>
52+
? Id<
53+
Pick<
54+
Required<CaseReducers[ReducerName]>,
55+
'fulfilled' | 'rejected' | 'pending' | 'settled'
56+
>
57+
>
58+
: never
59+
}
60+
}
61+
>
62+
}
63+
}
64+
65+
export interface AsyncThunkSliceReducerConfig<
66+
State,
67+
ThunkArg extends any,
68+
Returned = unknown,
69+
ThunkApiConfig extends AsyncThunkConfig = {},
70+
> {
71+
pending?: CaseReducer<
72+
State,
73+
ReturnType<AsyncThunk<Returned, ThunkArg, ThunkApiConfig>['pending']>
74+
>
75+
rejected?: CaseReducer<
76+
State,
77+
ReturnType<AsyncThunk<Returned, ThunkArg, ThunkApiConfig>['rejected']>
78+
>
79+
fulfilled?: CaseReducer<
80+
State,
81+
ReturnType<AsyncThunk<Returned, ThunkArg, ThunkApiConfig>['fulfilled']>
82+
>
83+
settled?: CaseReducer<
84+
State,
85+
ReturnType<
86+
AsyncThunk<Returned, ThunkArg, ThunkApiConfig>['rejected' | 'fulfilled']
87+
>
88+
>
89+
options?: AsyncThunkOptions<ThunkArg, ThunkApiConfig>
90+
}
91+
92+
export interface AsyncThunkSliceReducerDefinition<
93+
State,
94+
ThunkArg extends any,
95+
Returned = unknown,
96+
ThunkApiConfig extends AsyncThunkConfig = {},
97+
> extends AsyncThunkSliceReducerConfig<
98+
State,
99+
ThunkArg,
100+
Returned,
101+
ThunkApiConfig
102+
>,
103+
ReducerDefinition<ReducerType.asyncThunk> {
104+
payloadCreator: AsyncThunkPayloadCreator<Returned, ThunkArg, ThunkApiConfig>
105+
}
106+
107+
/**
108+
* Providing these as part of the config would cause circular types, so we disallow passing them
109+
*/
110+
type PreventCircular<ThunkApiConfig> = {
111+
[K in keyof ThunkApiConfig]: K extends 'state' | 'dispatch'
112+
? never
113+
: ThunkApiConfig[K]
114+
}
115+
116+
interface AsyncThunkCreator<
117+
State,
118+
CurriedThunkApiConfig extends
119+
PreventCircular<AsyncThunkConfig> = PreventCircular<AsyncThunkConfig>,
120+
> {
121+
<Returned, ThunkArg = void>(
122+
payloadCreator: AsyncThunkPayloadCreator<
123+
Returned,
124+
ThunkArg,
125+
CurriedThunkApiConfig
126+
>,
127+
config?: AsyncThunkSliceReducerConfig<
128+
State,
129+
ThunkArg,
130+
Returned,
131+
CurriedThunkApiConfig
132+
>,
133+
): AsyncThunkSliceReducerDefinition<
134+
State,
135+
ThunkArg,
136+
Returned,
137+
CurriedThunkApiConfig
138+
>
139+
<
140+
Returned,
141+
ThunkArg,
142+
ThunkApiConfig extends PreventCircular<AsyncThunkConfig> = {},
143+
>(
144+
payloadCreator: AsyncThunkPayloadCreator<
145+
Returned,
146+
ThunkArg,
147+
ThunkApiConfig
148+
>,
149+
config?: AsyncThunkSliceReducerConfig<
150+
State,
151+
ThunkArg,
152+
Returned,
153+
ThunkApiConfig
154+
>,
155+
): AsyncThunkSliceReducerDefinition<State, ThunkArg, Returned, ThunkApiConfig>
156+
withTypes<
157+
ThunkApiConfig extends PreventCircular<AsyncThunkConfig>,
158+
>(): AsyncThunkCreator<
159+
State,
160+
OverrideThunkApiConfigs<CurriedThunkApiConfig, ThunkApiConfig>
161+
>
162+
}
163+
164+
export const asyncThunkCreator: ReducerCreator<ReducerType.asyncThunk> = {
165+
type: ReducerType.asyncThunk,
166+
create: /* @__PURE__ */ (() => {
167+
function asyncThunk(
168+
payloadCreator: AsyncThunkPayloadCreator<any, any>,
169+
config: AsyncThunkSliceReducerConfig<any, any>,
170+
): AsyncThunkSliceReducerDefinition<any, any> {
171+
return {
172+
_reducerDefinitionType: ReducerType.asyncThunk,
173+
payloadCreator,
174+
...config,
175+
}
176+
}
177+
asyncThunk.withTypes = () => asyncThunk
178+
return asyncThunk as AsyncThunkCreator<any>
179+
})(),
180+
handle({ type, reducerName }, definition, context) {
181+
const { payloadCreator, fulfilled, pending, rejected, settled, options } =
182+
definition
183+
const thunk = createAsyncThunk(type, payloadCreator, options as any)
184+
context.exposeAction(reducerName, thunk)
185+
186+
if (fulfilled) {
187+
context.addCase(thunk.fulfilled, fulfilled)
188+
}
189+
if (pending) {
190+
context.addCase(thunk.pending, pending)
191+
}
192+
if (rejected) {
193+
context.addCase(thunk.rejected, rejected)
194+
}
195+
if (settled) {
196+
context.addMatcher(thunk.settled, settled)
197+
}
198+
199+
context.exposeCaseReducer(reducerName, {
200+
fulfilled: fulfilled || noop,
201+
pending: pending || noop,
202+
rejected: rejected || noop,
203+
settled: settled || noop,
204+
})
205+
},
206+
}
207+
208+
function noop() {}

0 commit comments

Comments
 (0)