1
1
import type {
2
- PayloadAction ,
3
2
Middleware ,
4
3
Dispatch ,
5
4
AnyAction ,
6
- MiddlewareAPI ,
7
5
Action ,
8
6
ThunkDispatch ,
9
7
} from '@reduxjs/toolkit'
10
8
import { createAction , nanoid } from '@reduxjs/toolkit'
11
9
12
- interface BaseActionCreator < P , T extends string , M = never , E = never > {
13
- type : T
14
- match ( action : Action < unknown > ) : action is PayloadAction < P , T , M , E >
15
- }
16
-
17
- interface TypedActionCreator < Type extends string > {
18
- ( ...args : any [ ] ) : Action < Type >
19
- type : Type
20
- match : MatchFunction < any >
21
- }
22
-
23
- type AnyActionListenerPredicate < State > = (
24
- action : AnyAction ,
25
- currentState : State ,
26
- originalState : State
27
- ) => boolean
28
-
29
- type ListenerPredicate < Action extends AnyAction , State > = (
30
- action : AnyAction ,
31
- currentState : State ,
32
- originalState : State
33
- ) => action is Action
34
-
35
- interface ConditionFunction < State > {
36
- (
37
- predicate : AnyActionListenerPredicate < State > ,
38
- timeout ?: number
39
- ) : Promise < boolean >
40
- (
41
- predicate : AnyActionListenerPredicate < State > ,
42
- timeout ?: number
43
- ) : Promise < boolean >
44
- ( predicate : ( ) => boolean , timeout ?: number ) : Promise < boolean >
45
- }
46
-
47
- type MatchFunction < T > = ( v : any ) => v is T
48
-
49
- type TakePatternOutputWithoutTimeout <
50
- State ,
51
- Predicate extends AnyActionListenerPredicate < State >
52
- > = Predicate extends MatchFunction < infer Action >
53
- ? Promise < [ Action , State , State ] >
54
- : Promise < [ AnyAction , State , State ] >
55
-
56
- type TakePatternOutputWithTimeout <
57
- State ,
58
- Predicate extends AnyActionListenerPredicate < State >
59
- > = Predicate extends MatchFunction < infer Action >
60
- ? Promise < [ Action , State , State ] | null >
61
- : Promise < [ AnyAction , State , State ] | null >
62
-
63
- interface TakePattern < State > {
64
- < Predicate extends AnyActionListenerPredicate < State > > (
65
- predicate : Predicate
66
- ) : TakePatternOutputWithoutTimeout < State , Predicate >
67
- < Predicate extends AnyActionListenerPredicate < State > > (
68
- predicate : Predicate ,
69
- timeout : number
70
- ) : TakePatternOutputWithTimeout < State , Predicate > ;
71
- < Predicate extends AnyActionListenerPredicate < State > > (
72
- predicate : Predicate ,
73
- timeout ?: number | undefined
74
- ) : Promise < [ AnyAction , State , State ] | null > ;
75
- }
76
-
77
- export interface HasMatchFunction < T > {
78
- match : MatchFunction < T >
79
- }
10
+ import type {
11
+ ActionListener ,
12
+ AddListenerOverloads ,
13
+ BaseActionCreator ,
14
+ AnyActionListenerPredicate ,
15
+ CreateListenerMiddlewareOptions ,
16
+ ConditionFunction ,
17
+ ListenerPredicate ,
18
+ TypedActionCreator ,
19
+ TypedAddListener ,
20
+ TypedAddListenerAction ,
21
+ TypedCreateListenerEntry ,
22
+ RemoveListenerAction ,
23
+ FallbackAddListenerOptions ,
24
+ ListenerEntry ,
25
+ ListenerErrorHandler ,
26
+ Unsubscribe ,
27
+ MiddlewarePhase ,
28
+ WithMiddlewareType ,
29
+ TakePattern ,
30
+ } from './types'
31
+
32
+ export type {
33
+ ActionListener ,
34
+ ActionListenerMiddleware ,
35
+ ActionListenerMiddlewareAPI ,
36
+ ActionListenerOptions ,
37
+ CreateListenerMiddlewareOptions ,
38
+ MiddlewarePhase ,
39
+ When ,
40
+ ListenerErrorHandler ,
41
+ TypedAddListener ,
42
+ TypedAddListenerAction ,
43
+ Unsubscribe ,
44
+ } from './types'
80
45
81
46
function assertFunction (
82
47
func : unknown ,
@@ -87,196 +52,11 @@ function assertFunction(
87
52
}
88
53
}
89
54
90
- type Unsubscribe = ( ) => void
91
-
92
- type GuardedType < T > = T extends ( x : any , ...args : unknown [ ] ) => x is infer T
93
- ? T
94
- : never
95
-
96
- type ListenerPredicateGuardedActionType < T > = T extends ListenerPredicate <
97
- infer Action ,
98
- any
99
- >
100
- ? Action
101
- : never
102
-
103
- const declaredMiddlewareType : unique symbol = undefined as any
104
- export type WithMiddlewareType < T extends Middleware < any , any , any > > = {
105
- [ declaredMiddlewareType ] : T
106
- }
107
-
108
- export type MiddlewarePhase = 'beforeReducer' | 'afterReducer'
109
-
110
55
const defaultWhen : MiddlewarePhase = 'afterReducer'
111
56
const actualMiddlewarePhases = [ 'beforeReducer' , 'afterReducer' ] as const
112
57
113
- export type When = MiddlewarePhase | 'both' | undefined
114
-
115
- /**
116
- * @alpha
117
- */
118
- export interface ActionListenerMiddlewareAPI < S , D extends Dispatch < AnyAction > >
119
- extends MiddlewareAPI < D , S > {
120
- getOriginalState : ( ) => S
121
- unsubscribe ( ) : void
122
- subscribe ( ) : void
123
- condition : ConditionFunction < S >
124
- take : TakePattern < S >
125
- currentPhase : MiddlewarePhase
126
- // TODO Figure out how to pass this through the other types correctly
127
- extra : unknown
128
- }
129
-
130
- /**
131
- * @alpha
132
- */
133
- export type ActionListener <
134
- A extends AnyAction ,
135
- S ,
136
- D extends Dispatch < AnyAction >
137
- > = ( action : A , api : ActionListenerMiddlewareAPI < S , D > ) => void
138
-
139
- export interface ListenerErrorHandler {
140
- ( error : unknown ) : void
141
- }
142
-
143
- export interface ActionListenerOptions {
144
- /**
145
- * Determines if the listener runs 'before' or 'after' the reducers have been called.
146
- * If set to 'before', calling `api.stopPropagation()` from the listener becomes possible.
147
- * Defaults to 'before'.
148
- */
149
- when ?: When
150
- }
151
-
152
- export interface CreateListenerMiddlewareOptions < ExtraArgument = unknown > {
153
- extra ?: ExtraArgument
154
- /**
155
- * Receives synchronous errors that are raised by `listener` and `listenerOption.predicate`.
156
- */
157
- onError ?: ListenerErrorHandler
158
- }
159
-
160
- /**
161
- * The possible overloads and options for defining a listener. The return type of each function is specified as a generic arg, so the overloads can be reused for multiple different functions
162
- */
163
- interface AddListenerOverloads <
164
- Return ,
165
- S = unknown ,
166
- D extends Dispatch = ThunkDispatch < S , unknown , AnyAction >
167
- > {
168
- /** Accepts a "listener predicate" that is also a TS type predicate for the action*/
169
- < MA extends AnyAction , LP extends ListenerPredicate < MA , S > > (
170
- options : {
171
- actionCreator ?: never
172
- type ?: never
173
- matcher ?: never
174
- predicate : LP
175
- listener : ActionListener < ListenerPredicateGuardedActionType < LP > , S , D >
176
- } & ActionListenerOptions
177
- ) : Return
178
-
179
- /** Accepts an RTK action creator, like `incrementByAmount` */
180
- < C extends TypedActionCreator < any > > (
181
- options : {
182
- actionCreator : C
183
- type ?: never
184
- matcher ?: never
185
- predicate ?: never
186
- listener : ActionListener < ReturnType < C > , S , D >
187
- } & ActionListenerOptions
188
- ) : Return
189
-
190
- /** Accepts a specific action type string */
191
- < T extends string > (
192
- options : {
193
- actionCreator ?: never
194
- type : T
195
- matcher ?: never
196
- predicate ?: never
197
- listener : ActionListener < Action < T > , S , D >
198
- } & ActionListenerOptions
199
- ) : Return
200
-
201
- /** Accepts an RTK matcher function, such as `incrementByAmount.match` */
202
- < MA extends AnyAction , M extends MatchFunction < MA > > (
203
- options : {
204
- actionCreator ?: never
205
- type ?: never
206
- matcher : M
207
- predicate ?: never
208
- listener : ActionListener < GuardedType < M > , S , D >
209
- } & ActionListenerOptions
210
- ) : Return
211
-
212
- /** Accepts a "listener predicate" that just returns a boolean, no type assertion */
213
- < LP extends AnyActionListenerPredicate < S > > (
214
- options : {
215
- actionCreator ?: never
216
- type ?: never
217
- matcher ?: never
218
- predicate : LP
219
- listener : ActionListener < AnyAction , S , D >
220
- } & ActionListenerOptions
221
- ) : Return
222
- }
223
-
224
- interface RemoveListenerOverloads <
225
- S = unknown ,
226
- D extends Dispatch = ThunkDispatch < S , unknown , AnyAction >
227
- > {
228
- < C extends TypedActionCreator < any > > (
229
- actionCreator : C ,
230
- listener : ActionListener < ReturnType < C > , S , D >
231
- ) : boolean
232
- ( type : string , listener : ActionListener < AnyAction , S , D > ) : boolean
233
- }
234
-
235
- /** A "pre-typed" version of `addListenerAction`, so the listener args are well-typed */
236
- export type TypedAddListenerAction <
237
- S ,
238
- D extends Dispatch < AnyAction > = ThunkDispatch < S , unknown , AnyAction > ,
239
- Payload = ListenerEntry < S , D > ,
240
- T extends string = 'actionListenerMiddleware/add'
241
- > = BaseActionCreator < Payload , T > &
242
- AddListenerOverloads < PayloadAction < Payload , T > , S , D >
243
-
244
- /** A "pre-typed" version of `middleware.addListener`, so the listener args are well-typed */
245
- export type TypedAddListener <
246
- S ,
247
- D extends Dispatch < AnyAction > = ThunkDispatch < S , unknown , AnyAction >
248
- > = AddListenerOverloads < Unsubscribe , S , D >
249
-
250
- /** @internal An single listener entry */
251
- type ListenerEntry <
252
- S = unknown ,
253
- D extends Dispatch < AnyAction > = Dispatch < AnyAction >
254
- > = {
255
- id : string
256
- when : When
257
- listener : ActionListener < any , S , D >
258
- unsubscribe : ( ) => void
259
- type ?: string
260
- predicate : ListenerPredicate < AnyAction , S >
261
- }
262
-
263
- /** A "pre-typed" version of `createListenerEntry`, so the listener args are well-typed */
264
- export type TypedCreateListenerEntry <
265
- S ,
266
- D extends Dispatch < AnyAction > = ThunkDispatch < S , unknown , AnyAction >
267
- > = AddListenerOverloads < ListenerEntry < S , D > , S , D >
268
-
269
- // A shorthand form of the accepted args, solely so that `createListenerEntry` has validly-typed conditional logic when checking the options contents
270
- type FallbackAddListenerOptions = (
271
- | { actionCreator : TypedActionCreator < string > }
272
- | { type : string }
273
- | { matcher : MatchFunction < any > }
274
- | { predicate : ListenerPredicate < any , any > }
275
- ) &
276
- ActionListenerOptions & { listener : ActionListener < any , any , any > }
277
-
278
58
function createTakePattern < S > (
279
- addListener : AddListenerOverloads < Unsubscribe , S , Dispatch < AnyAction > >
59
+ addListener : AddListenerOverloads < Unsubscribe , S , Dispatch < AnyAction > >
280
60
) : TakePattern < S > {
281
61
async function take < P extends AnyActionListenerPredicate < S > > (
282
62
predicate : P ,
@@ -352,27 +132,6 @@ export const createListenerEntry: TypedCreateListenerEntry<unknown> = (
352
132
return entry
353
133
}
354
134
355
- export type ActionListenerMiddleware <
356
- S = unknown ,
357
- // TODO Carry through the thunk extra arg somehow?
358
- D extends ThunkDispatch < S , unknown , AnyAction > = ThunkDispatch <
359
- S ,
360
- unknown ,
361
- AnyAction
362
- > ,
363
- ExtraArgument = unknown
364
- > = Middleware <
365
- {
366
- ( action : Action < 'actionListenerMiddleware/add' > ) : Unsubscribe
367
- } ,
368
- S ,
369
- D
370
- > & {
371
- addListener : AddListenerOverloads < Unsubscribe , S , D >
372
- removeListener : RemoveListenerOverloads < S , D >
373
- addListenerAction : TypedAddListenerAction < S , D >
374
- }
375
-
376
135
/**
377
136
* Safely reports errors to the `errorHandler` provided.
378
137
* Errors that occur inside `errorHandler` are notified in a new task.
@@ -412,18 +171,6 @@ export const addListenerAction = createAction(
412
171
}
413
172
) as TypedAddListenerAction < unknown >
414
173
415
- interface RemoveListenerAction <
416
- A extends AnyAction ,
417
- S ,
418
- D extends Dispatch < AnyAction >
419
- > {
420
- type : 'actionListenerMiddleware/remove'
421
- payload : {
422
- type : string
423
- listener : ActionListener < A , S , D >
424
- }
425
- }
426
-
427
174
/**
428
175
* @alpha
429
176
*/
0 commit comments