@@ -46,6 +46,34 @@ interface ConditionFunction<State> {
46
46
47
47
type MatchFunction < T > = ( v : any ) => v is T
48
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
+
49
77
export interface HasMatchFunction < T > {
50
78
match : MatchFunction < T >
51
79
}
@@ -93,6 +121,7 @@ export interface ActionListenerMiddlewareAPI<S, D extends Dispatch<AnyAction>>
93
121
unsubscribe ( ) : void
94
122
subscribe ( ) : void
95
123
condition : ConditionFunction < S >
124
+ take : TakePattern < S >
96
125
currentPhase : MiddlewarePhase
97
126
// TODO Figure out how to pass this through the other types correctly
98
127
extra : unknown
@@ -246,6 +275,49 @@ type FallbackAddListenerOptions = (
246
275
) &
247
276
ActionListenerOptions & { listener : ActionListener < any , any , any > }
248
277
278
+ function createTakePattern < S > (
279
+ addListener : AddListenerOverloads < Unsubscribe , S , Dispatch < AnyAction > >
280
+ ) : TakePattern < S > {
281
+ async function take < P extends AnyActionListenerPredicate < S > > (
282
+ predicate : P ,
283
+ timeout : number | undefined
284
+ ) {
285
+ let unsubscribe : Unsubscribe = ( ) => { }
286
+
287
+ const tuplePromise = new Promise < [ AnyAction , S , S ] > ( ( resolve ) => {
288
+ unsubscribe = addListener ( {
289
+ predicate : predicate as any ,
290
+ listener : ( action , listenerApi ) : void => {
291
+ // One-shot listener that cleans up as soon as the predicate resolves
292
+ listenerApi . unsubscribe ( )
293
+ resolve ( [
294
+ action ,
295
+ listenerApi . getState ( ) ,
296
+ listenerApi . getOriginalState ( ) ,
297
+ ] )
298
+ } ,
299
+ } )
300
+ } )
301
+
302
+ if ( timeout === undefined ) {
303
+ return tuplePromise
304
+ }
305
+
306
+ const timedOutPromise = new Promise < null > ( ( resolve , reject ) => {
307
+ setTimeout ( ( ) => {
308
+ resolve ( null )
309
+ } , timeout )
310
+ } )
311
+
312
+ const result = await Promise . race ( [ tuplePromise , timedOutPromise ] )
313
+
314
+ unsubscribe ( )
315
+ return result
316
+ }
317
+
318
+ return take as TakePattern < S >
319
+ }
320
+
249
321
/** Accepts the possible options for creating a listener, and returns a formatted listener entry */
250
322
export const createListenerEntry : TypedCreateListenerEntry < unknown > = (
251
323
options : FallbackAddListenerOptions
@@ -466,39 +538,9 @@ export function createActionListenerMiddleware<
466
538
return true
467
539
}
468
540
469
- const condition : ConditionFunction < S > = async ( predicate , timeout ) => {
470
- let unsubscribe : Unsubscribe = ( ) => { }
471
-
472
- const conditionSucceededPromise = new Promise < boolean > (
473
- ( resolve , reject ) => {
474
- unsubscribe = addListener ( {
475
- predicate,
476
- listener : ( action , listenerApi ) => {
477
- // One-shot listener that cleans up as soon as the predicate resolves
478
- listenerApi . unsubscribe ( )
479
- resolve ( true )
480
- } ,
481
- } )
482
- }
483
- )
484
-
485
- if ( timeout === undefined ) {
486
- return conditionSucceededPromise
487
- }
488
-
489
- const timedOutPromise = new Promise < boolean > ( ( resolve , reject ) => {
490
- setTimeout ( ( ) => {
491
- resolve ( false )
492
- } , timeout )
493
- } )
494
-
495
- const result = await Promise . race ( [
496
- conditionSucceededPromise ,
497
- timedOutPromise ,
498
- ] )
499
-
500
- unsubscribe ( )
501
- return result
541
+ const take = createTakePattern ( addListener )
542
+ const condition : ConditionFunction < S > = ( predicate , timeout ) => {
543
+ return take ( predicate , timeout ) . then ( Boolean )
502
544
}
503
545
504
546
const middleware : Middleware <
@@ -558,6 +600,7 @@ export function createActionListenerMiddleware<
558
600
...api ,
559
601
getOriginalState,
560
602
condition,
603
+ take,
561
604
currentPhase,
562
605
extra,
563
606
unsubscribe : entry . unsubscribe ,
0 commit comments