@flex-development/when 2.0.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,3 +1,85 @@
1
+ /**
2
+ * @file Interfaces - PromiseLike
3
+ * @module when/interfaces/PromiseLike
4
+ */
5
+ declare global {
6
+ interface PromiseLike<T> {
7
+ /**
8
+ * Attach callbacks for resolution and/or rejection.
9
+ *
10
+ * @template {any} [S=T]
11
+ * The next resolved value on success
12
+ * @template {any} [F=never]
13
+ * The next resolved value on failure
14
+ *
15
+ * @this {unknown}
16
+ *
17
+ * @param {((value: T) => PromiseLike<S> | S) | null | undefined} [succ]
18
+ * The callback to execute when the thenable is resolved
19
+ * @param {((reason: any) => F | PromiseLike<F>) | null | undefined} [fail]
20
+ * The callback to execute when the thenable is rejected
21
+ * @return {PromiseLike<F | S>}
22
+ * The next promise-like object
23
+ */
24
+ then<S = T, F = never>(succ?: ((value: T) => PromiseLike<S> | S) | null | undefined, fail?: ((reason: any) => F | PromiseLike<F>) | null | undefined): PromiseLike<F | S>;
25
+ }
26
+ }
27
+
28
+ /**
29
+ * @file Interfaces - Catchable
30
+ * @module when/interfaces/Catchable
31
+ */
32
+
33
+ /**
34
+ * A thenable that can be caught.
35
+ *
36
+ * @see {@linkcode Thenable}
37
+ *
38
+ * @template {any} [T=any]
39
+ * The resolved value
40
+ *
41
+ * @extends {Thenable<T>}
42
+ */
43
+ interface Catchable<T = any> extends Thenable<T> {
44
+ /**
45
+ * Attach a callback only to be invoked on rejection.
46
+ *
47
+ * @see {@linkcode Catch}
48
+ *
49
+ * @override
50
+ */
51
+ catch: Catch<T>;
52
+ }
53
+
54
+ /**
55
+ * @file Interfaces - Finalizable
56
+ * @module when/interfaces/Finalizable
57
+ */
58
+
59
+ /**
60
+ * A thenable that can be finalized.
61
+ *
62
+ * @see {@linkcode Thenable}
63
+ *
64
+ * @template {any} [T=any]
65
+ * The resolved value
66
+ *
67
+ * @extends {Thenable<T>}
68
+ */
69
+ interface Finalizable<T = any> extends Thenable<T> {
70
+ /**
71
+ * Attach a callback only to be invoked
72
+ * on settlement (fulfillment or rejection).
73
+ *
74
+ * > 👉 **Note**: The resolved value cannot be modified from the callback.
75
+ *
76
+ * @see {@linkcode Finally}
77
+ *
78
+ * @override
79
+ */
80
+ finally: Finally<T>;
81
+ }
82
+
1
83
  /**
2
84
  * @file Interfaces - Options
3
85
  * @module when/interfaces/Options
@@ -60,8 +142,109 @@ interface Options<T = any, Next = any, Failure = Next, Args extends readonly any
60
142
  * @since 2.0.0
61
143
  */
62
144
  fail?: Fail<Failure, Error, This> | null | undefined;
145
+ /**
146
+ * The callback to invoke after chaining completes, whether the operation
147
+ * succeeds or fails.
148
+ *
149
+ * It runs exactly once after {@linkcode chain} and {@linkcode fail}, cannot
150
+ * affect the resolved value, and does not intercept errors.
151
+ *
152
+ * @see {@linkcode Finish}
153
+ *
154
+ * @since 3.0.0
155
+ */
156
+ finish?: Finish<This> | null | undefined;
63
157
  }
64
158
 
159
+ /**
160
+ * @file Interfaces - Thenable
161
+ * @module when/interfaces/Thenable
162
+ */
163
+
164
+ /**
165
+ * The completion of an asynchronous operation, and the minimal structural
166
+ * contract required by `when` to treat a value as asynchronous.
167
+ *
168
+ * Unlike {@linkcode PromiseLike}, this interface allows maybe-callable `catch`
169
+ * and `finally` methods, which when present, are used by `when` to ensure
170
+ * failures are handled and post-processing hooks are executed without forcing
171
+ * promise allocation.
172
+ *
173
+ * Maybe-callable methods are named so because they are not required,
174
+ * and may be a method implementation, `null`, or `undefined`.
175
+ *
176
+ * @template {any} [T=any]
177
+ * The resolved value
178
+ */
179
+ interface Thenable<T = any> {
180
+ /**
181
+ * Attach a callback only to be invoked on rejection.
182
+ *
183
+ * @see {@linkcode Catch}
184
+ */
185
+ catch?: Catch<T> | null | undefined;
186
+ /**
187
+ * Attach a callback only to be invoked
188
+ * on settlement (fulfillment or rejection).
189
+ *
190
+ * > 👉 **Note**: The resolved value cannot be modified from the callback.
191
+ *
192
+ * @see {@linkcode Finally}
193
+ */
194
+ finally?: Finally<T> | null | undefined;
195
+ /**
196
+ * Attach callbacks to be invoked on resolution (fulfillment)
197
+ * and/or rejection.
198
+ *
199
+ * @see {@linkcode Then}
200
+ */
201
+ then: Then<T>;
202
+ }
203
+
204
+ /**
205
+ * @file isCatchable
206
+ * @module when/lib/isCatchable
207
+ */
208
+
209
+ /**
210
+ * Check if `value` looks like a `Thenable` that can be caught.
211
+ *
212
+ * @see {@linkcode Catchable}
213
+ *
214
+ * @template {any} T
215
+ * The resolved value
216
+ *
217
+ * @this {void}
218
+ *
219
+ * @param {unknown} value
220
+ * The thing to check
221
+ * @return {value is Catchable<T>}
222
+ * `true` if `value` is a thenable with a `catch` method, `false` otherwise
223
+ */
224
+ declare function isCatchable<T>(this: void, value: unknown): value is Catchable<T>;
225
+
226
+ /**
227
+ * @file isFinalizable
228
+ * @module when/lib/isFinalizable
229
+ */
230
+
231
+ /**
232
+ * Check if `value` looks like a thenable that can be finalized.
233
+ *
234
+ * @see {@linkcode Finalizable}
235
+ *
236
+ * @template {any} T
237
+ * The resolved value
238
+ *
239
+ * @this {void}
240
+ *
241
+ * @param {unknown} value
242
+ * The thing to check
243
+ * @return {value is Finalizable<T>}
244
+ * `true` if `value` is a thenable with a `finally` method, `false` otherwise
245
+ */
246
+ declare function isFinalizable<T>(this: void, value: unknown): value is Finalizable<T>;
247
+
65
248
  /**
66
249
  * @file isPromise
67
250
  * @module when/lib/isPromise
@@ -69,8 +252,8 @@ interface Options<T = any, Next = any, Failure = Next, Args extends readonly any
69
252
  /**
70
253
  * Check if `value` looks like a {@linkcode Promise}.
71
254
  *
72
- * > 👉 **Note**: This function intentionally performs a structural check
73
- * > instead of a brand check.
255
+ * > 👉 **Note**: This function intentionally performs structural checks
256
+ * > instead of brand checks.
74
257
  * > It does not rely on `instanceof Promise` or constructors, making it
75
258
  * > compatible with cross-realm promises and custom thenables.
76
259
  *
@@ -83,18 +266,21 @@ interface Options<T = any, Next = any, Failure = Next, Args extends readonly any
83
266
  *
84
267
  * @param {unknown} value
85
268
  * The thing to check
269
+ * @param {boolean | null | undefined} [finalizable=true]
270
+ * Whether a `finally` method is required.\
271
+ * When `false`, only `then` and `catch` are checked
86
272
  * @return {value is Promise<T>}
87
- * `true` if `value` is a thenable with a `catch` method, `false` otherwise
273
+ * `true` if `value` is a thenable with a `catch` method,
274
+ * and `finally` method (if requested), `false` otherwise
88
275
  */
89
- declare function isPromise<T>(this: void, value: unknown): value is Promise<T>;
276
+ declare function isPromise<T>(this: void, value: unknown, finalizable?: boolean | null | undefined): value is Promise<T>;
90
277
 
91
278
  /**
92
- * @file isThenable
93
- * @module when/lib/isThenable
279
+ * @file isPromiseLike
280
+ * @module when/lib/isPromiseLike
94
281
  */
95
282
  /**
96
- * Check if `value` looks like a thenable,
97
- * i.e. a {@linkcode PromiseLike} object.
283
+ * Check if `value` looks like a {@linkcode PromiseLike} structure.
98
284
  *
99
285
  * @template {any} T
100
286
  * The resolved value
@@ -107,7 +293,30 @@ declare function isPromise<T>(this: void, value: unknown): value is Promise<T>;
107
293
  * `true` if `value` is an object or function with a `then` method,
108
294
  * `false` otherwise
109
295
  */
110
- declare function isThenable<T>(this: void, value: unknown): value is PromiseLike<T>;
296
+ declare function isPromiseLike<T>(this: void, value: unknown): value is PromiseLike<T>;
297
+
298
+ /**
299
+ * @file isThenable
300
+ * @module when/lib/isThenable
301
+ */
302
+
303
+ /**
304
+ * Check if `value` looks like a {@linkcode Thenable}.
305
+ *
306
+ * @see {@linkcode Thenable}
307
+ *
308
+ * @template {any} T
309
+ * The resolved value
310
+ *
311
+ * @this {void}
312
+ *
313
+ * @param {unknown} value
314
+ * The thing to check
315
+ * @return {value is Thenable<T>}
316
+ * `true` if `value` is an object or function with a `then` method,
317
+ * and maybe-callable methods `catch` and/or `finally`, `false` otherwise
318
+ */
319
+ declare function isThenable<T>(this: void, value: unknown): value is Thenable<T>;
111
320
 
112
321
  /**
113
322
  * @file when
@@ -130,6 +339,8 @@ declare function isThenable<T>(this: void, value: unknown): value is PromiseLike
130
339
  * The chain function arguments
131
340
  * @template {any} [This=any]
132
341
  * The `this` context
342
+ * @template {Awaitable<Next>} [Result=Awaitable<Next>]
343
+ * The next awaitable
133
344
  *
134
345
  * @this {void}
135
346
  *
@@ -143,10 +354,10 @@ declare function isThenable<T>(this: void, value: unknown): value is PromiseLike
143
354
  * The `this` context of the chain and `fail` callbacks
144
355
  * @param {Args} args
145
356
  * The arguments to pass to the chain callback
146
- * @return {Awaitable<Next>}
357
+ * @return {Result}
147
358
  * The next awaitable
148
359
  */
149
- declare function when<T, Next = any, Args extends any[] = any[], This = unknown>(this: void, value: Awaitable<T>, chain: Chain<T, Next, Args, This>, fail?: null | undefined, context?: This | null | undefined, ...args: Args): Awaitable<Next>;
360
+ declare function when<T, Next = any, Args extends any[] = any[], This = unknown, Result extends Awaitable<Next> = Awaitable<Next>>(this: void, value: Awaitable<T>, chain: Chain<T, Next, Args, This>, fail?: null | undefined, context?: This | null | undefined, ...args: Args): Result;
150
361
  /**
151
362
  * Chain a callback, calling the function after `value` is resolved,
152
363
  * or immediately if `value` is not a thenable.
@@ -167,6 +378,8 @@ declare function when<T, Next = any, Args extends any[] = any[], This = unknown>
167
378
  * The error to possibly handle
168
379
  * @template {any} [This=any]
169
380
  * The `this` context
381
+ * @template {Awaitable<Failure | Next>} [Result=Awaitable<Failure | Next>]
382
+ * The next awaitable
170
383
  *
171
384
  * @this {void}
172
385
  *
@@ -180,10 +393,10 @@ declare function when<T, Next = any, Args extends any[] = any[], This = unknown>
180
393
  * The `this` context of the chain and `fail` callbacks
181
394
  * @param {Args} args
182
395
  * The arguments to pass to the chain callback
183
- * @return {Awaitable<Failure | Next>}
396
+ * @return {Result}
184
397
  * The next awaitable
185
398
  */
186
- declare function when<T, Next = any, Failure = Next, Args extends any[] = any[], Error = any, This = unknown>(this: void, value: Awaitable<T>, chain: Chain<T, Next, Args, This>, fail?: Fail<Failure, Error, This> | null | undefined, context?: This | null | undefined, ...args: Args): Awaitable<Failure | Next>;
399
+ declare function when<T, Next = any, Failure = Next, Args extends any[] = any[], Error = any, This = unknown, Result extends Awaitable<Failure | Next> = Awaitable<Failure | Next>>(this: void, value: Awaitable<T>, chain: Chain<T, Next, Args, This>, fail?: Fail<Failure, Error, This> | null | undefined, context?: This | null | undefined, ...args: Args): Result;
187
400
  /**
188
401
  * Chain a callback, calling the function after `value` is resolved,
189
402
  * or immediately if `value` is not a thenable.
@@ -203,6 +416,8 @@ declare function when<T, Next = any, Failure = Next, Args extends any[] = any[],
203
416
  * The error to possibly handle
204
417
  * @template {any} [This=unknown]
205
418
  * The `this` context
419
+ * @template {Awaitable<Failure | Next>} [Result=Awaitable<Failure | Next>]
420
+ * The next awaitable
206
421
  *
207
422
  * @this {void}
208
423
  *
@@ -210,22 +425,52 @@ declare function when<T, Next = any, Failure = Next, Args extends any[] = any[],
210
425
  * The current awaitable
211
426
  * @param {Options<T, Next, Failure, Args, Error, This>} chain
212
427
  * Options for chaining
213
- * @return {Awaitable<Failure | Next>}
428
+ * @return {Result}
214
429
  * The next awaitable
215
430
  */
216
- declare function when<T, Next = any, Failure = Next, Args extends any[] = any[], Error = any, This = unknown>(this: void, value: Awaitable<T>, chain: Options<T, Next, Failure, Args, Error, This>): Awaitable<Failure | Next>;
431
+ declare function when<T, Next = any, Failure = Next, Args extends any[] = any[], Error = any, This = unknown, Result extends Awaitable<Failure | Next> = Awaitable<Failure | Next>>(this: void, value: Awaitable<T>, chain: Options<T, Next, Failure, Args, Error, This>): Result;
217
432
 
218
433
  /**
219
434
  * @file Type Aliases - Awaitable
220
435
  * @module when/types/Awaitable
221
436
  */
437
+
222
438
  /**
223
439
  * A synchronous or thenable value.
224
440
  *
441
+ * @see {@linkcode Thenable}
442
+ *
225
443
  * @template {any} T
226
444
  * The resolved value
227
445
  */
228
- type Awaitable<T> = PromiseLike<T> | T;
446
+ type Awaitable<T> = Thenable<T> | T;
447
+
448
+ /**
449
+ * @file Type Aliases - Catch
450
+ * @module when/types/Catch
451
+ */
452
+
453
+ /**
454
+ * Attach a callback only for the rejection of a `Thenable`.
455
+ *
456
+ * @see {@linkcode OnRejected}
457
+ * @see {@linkcode Thenable}
458
+ *
459
+ * @template {any} [T=unknown]
460
+ * The resolved value
461
+ * @template {any} [Reason=any]
462
+ * The reason for the rejection
463
+ * @template {any} [Next=never]
464
+ * The next resolved value
465
+ *
466
+ * @this {any}
467
+ *
468
+ * @param {OnRejected<Next, Reason> | null | undefined} [onrejected]
469
+ * The callback to execute when the thenable is rejected
470
+ * @return {Thenable<Next | T>}
471
+ * The next thenable
472
+ */
473
+ type Catch<T = unknown, Reason = any> = <Next = never>(this: any, onrejected?: OnRejected<Next, Reason> | null | undefined) => Thenable<Next | T>;
229
474
 
230
475
  /**
231
476
  * @file Type Aliases - Chain
@@ -269,19 +514,158 @@ type Chain<T = any, Next = any, Args extends readonly any[] = any[], This = unkn
269
514
  *
270
515
  * @template {any} [Next=any]
271
516
  * The next resolved value
272
- * @template {any} [Error=any]
273
- * The error to handle
517
+ * @template {any} [Reason=any]
518
+ * The reason for the failure
519
+ * @template {any} [This=unknown]
520
+ * The `this` context
521
+ *
522
+ * @this {This}
523
+ *
524
+ * @param {Reason} reason
525
+ * The reason for the failure
526
+ * @return {Awaitable<Next>}
527
+ * The next awaitable
528
+ */
529
+ type Fail<Next = any, Reason = any, This = unknown> = (this: This, reason: Reason) => Awaitable<Next>;
530
+
531
+ /**
532
+ * @file Type Aliases - Finally
533
+ * @module when/types/Finally
534
+ */
535
+
536
+ /**
537
+ * Attach a callback that is invoked only when a `Thenable`
538
+ * is settled (fulfilled or rejected).
539
+ *
540
+ * > 👉 **Note**: The resolved value cannot be modified from the callback.
541
+ *
542
+ * @see {@linkcode OnFinally}
543
+ * @see {@linkcode Thenable}
544
+ *
545
+ * @template {any} [T=unknown]
546
+ * The resolved value
547
+ *
548
+ * @this {any}
549
+ *
550
+ * @param {OnFinally | null | undefined} [onfinally]
551
+ * The callback to execute when the thenable is settled
552
+ * @return {Thenable<T>}
553
+ * The next thenable
554
+ */
555
+ type Finally<T = unknown> = (this: any, onfinally?: OnFinally | null | undefined) => Thenable<T>;
556
+
557
+ /**
558
+ * @file Type Aliases - Finish
559
+ * @module when/types/Finish
560
+ */
561
+ /**
562
+ * A post-processing hook invoked exactly once after an awaitable settles,
563
+ * regardless of success or failure.
564
+ *
565
+ * The resolved value cannot be modified from the hook,
566
+ * and any error is re-thrown after execution.
567
+ *
274
568
  * @template {any} [This=unknown]
275
569
  * The `this` context
276
570
  *
277
571
  * @this {This}
278
572
  *
279
- * @param {unknown} e
280
- * The error
573
+ * @return {undefined | void}
574
+ */
575
+ type Finish<This = unknown> = (this: This) => undefined | void;
576
+
577
+ /**
578
+ * @file Type Aliases - OnFinally
579
+ * @module when/types/OnFinally
580
+ */
581
+ /**
582
+ * The callback to execute when a `Thenable` is settled (fulfilled or rejected).
583
+ *
584
+ * @this {unknown}
585
+ *
586
+ * @return {undefined | void}
587
+ */
588
+ type OnFinally = (this: unknown) => undefined | void;
589
+
590
+ /**
591
+ * @file Type Aliases - OnFulfilled
592
+ * @module when/types/OnFulfilled
593
+ */
594
+
595
+ /**
596
+ * The callback to execute when a `Thenable` is resolved.
597
+ *
598
+ * @see {@linkcode Awaitable}
599
+ *
600
+ * @template {any} T
601
+ * The resolved value
602
+ * @template {any} [Next=T]
603
+ * The next resolved value
604
+ *
605
+ * @this {unknown}
606
+ *
607
+ * @param {T} value
608
+ * The resolved value
609
+ * @return {Awaitable<Next>}
610
+ * The next awaitable
611
+ */
612
+ type OnFulfilled<T, Next = T> = (this: unknown, value: T) => Awaitable<Next>;
613
+
614
+ /**
615
+ * @file Type Aliases - OnRejected
616
+ * @module when/types/OnRejected
617
+ */
618
+
619
+ /**
620
+ * The callback to execute when a `Thenable` is rejected.
621
+ *
622
+ * @see {@linkcode Awaitable}
623
+ *
624
+ * @template {any} Next
625
+ * The next resolved value
626
+ * @template {any} [Reason=any]
627
+ * The reason for the rejection
628
+ *
629
+ * @this {unknown}
630
+ *
631
+ * @param {Reason} reason
632
+ * The reason for the rejection
281
633
  * @return {Awaitable<Next>}
282
634
  * The next awaitable
283
635
  */
284
- type Fail<Next = any, Error = any, This = unknown> = (this: This, e: Error) => Awaitable<Next>;
636
+ type OnRejected<Next, Reason = any> = (this: unknown, reason: Reason) => Awaitable<Next>;
637
+
638
+ /**
639
+ * @file Type Aliases - Then
640
+ * @module when/types/Then
641
+ */
642
+
643
+ /**
644
+ * Attach callbacks for the resolution and/or rejection of a `Thenable`.
645
+ *
646
+ * @see {@linkcode OnFulfilled}
647
+ * @see {@linkcode OnRejected}
648
+ * @see {@linkcode Thenable}
649
+ *
650
+ * @template {any} [T=unknown]
651
+ * The previously resolved value
652
+ * @template {any} [Reason=any]
653
+ * The reason for a rejection
654
+ * @template {any} [Succ=T]
655
+ * The next resolved value on success
656
+ * @template {any} [Fail=never]
657
+ * The next resolved value on failure
658
+ *
659
+ * @this {any}
660
+ *
661
+ * @param {OnFulfilled<T, Succ> | null | undefined} [onfulfilled]
662
+ * The callback to execute when the thenable is resolved
663
+ * @param {OnRejected<Fail, Reason> | null | undefined} [onrejected]
664
+ * The callback to execute when the thenable is rejected
665
+ * @return {Thenable<Fail | Succ>}
666
+ * The next thenable
667
+ */
668
+ type Then<T = unknown, Reason = any> = <Succ = T, Fail = never>(this: any, onfulfilled?: OnFulfilled<T, Succ> | null | undefined, onrejected?: OnRejected<Fail, Reason> | null | undefined) => Thenable<Fail | Succ>;
285
669
 
286
- export { when as default, isPromise, isThenable as isPromiseLike, isThenable, when };
287
- export type { Awaitable, Chain, Fail, Options };
670
+ export { when as default, isCatchable, isFinalizable, isPromise, isPromiseLike, isThenable, when };
671
+ export type { Awaitable, Catch, Catchable, Chain, Fail, Finalizable, Finally, Finish, OnFinally, OnFulfilled, OnRejected, Options, Then, Thenable };
@@ -2,6 +2,9 @@
2
2
  * @file Entry Point - Library
3
3
  * @module when/lib
4
4
  */
5
+ export { default as isCatchable } from '#lib/is-catchable';
6
+ export { default as isFinalizable } from '#lib/is-finalizable';
5
7
  export { default as isPromise } from '#lib/is-promise';
6
- export { default as isPromiseLike, default as isThenable } from '#lib/is-thenable';
8
+ export { default as isPromiseLike } from '#lib/is-promise-like';
9
+ export { default as isThenable } from '#lib/is-thenable';
7
10
  export { default as when } from '#lib/when';
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @file isCatchable
3
+ * @module when/lib/isCatchable
4
+ */
5
+ import isThenable from '#lib/is-thenable';
6
+ /**
7
+ * Check if `value` looks like a `Thenable` that can be caught.
8
+ *
9
+ * @see {@linkcode Catchable}
10
+ *
11
+ * @template {any} T
12
+ * The resolved value
13
+ *
14
+ * @this {void}
15
+ *
16
+ * @param {unknown} value
17
+ * The thing to check
18
+ * @return {value is Catchable<T>}
19
+ * `true` if `value` is a thenable with a `catch` method, `false` otherwise
20
+ */
21
+ function isCatchable(value) {
22
+ return isThenable(value) && typeof value.catch === 'function';
23
+ }
24
+ export default isCatchable;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @file isFinalizable
3
+ * @module when/lib/isFinalizable
4
+ */
5
+ import isThenable from '#lib/is-thenable';
6
+ /**
7
+ * Check if `value` looks like a thenable that can be finalized.
8
+ *
9
+ * @see {@linkcode Finalizable}
10
+ *
11
+ * @template {any} T
12
+ * The resolved value
13
+ *
14
+ * @this {void}
15
+ *
16
+ * @param {unknown} value
17
+ * The thing to check
18
+ * @return {value is Finalizable<T>}
19
+ * `true` if `value` is a thenable with a `finally` method, `false` otherwise
20
+ */
21
+ function isFinalizable(value) {
22
+ return isThenable(value) && typeof value.finally === 'function';
23
+ }
24
+ export default isFinalizable;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @file isPromiseLike
3
+ * @module when/lib/isPromiseLike
4
+ */
5
+ /**
6
+ * Check if `value` looks like a {@linkcode PromiseLike} structure.
7
+ *
8
+ * @template {any} T
9
+ * The resolved value
10
+ *
11
+ * @this {void}
12
+ *
13
+ * @param {unknown} value
14
+ * The thing to check
15
+ * @return {value is PromiseLike<T>}
16
+ * `true` if `value` is an object or function with a `then` method,
17
+ * `false` otherwise
18
+ */
19
+ function isPromiseLike(value) {
20
+ if (typeof value !== 'function' && typeof value !== 'object')
21
+ return false;
22
+ return !!value && 'then' in value && typeof value.then === 'function';
23
+ }
24
+ export default isPromiseLike;
@@ -2,12 +2,14 @@
2
2
  * @file isPromise
3
3
  * @module when/lib/isPromise
4
4
  */
5
+ import isCatchable from '#lib/is-catchable';
6
+ import isFinalizable from '#lib/is-finalizable';
5
7
  import isThenable from '#lib/is-thenable';
6
8
  /**
7
9
  * Check if `value` looks like a {@linkcode Promise}.
8
10
  *
9
- * > 👉 **Note**: This function intentionally performs a structural check
10
- * > instead of a brand check.
11
+ * > 👉 **Note**: This function intentionally performs structural checks
12
+ * > instead of brand checks.
11
13
  * > It does not rely on `instanceof Promise` or constructors, making it
12
14
  * > compatible with cross-realm promises and custom thenables.
13
15
  *
@@ -20,12 +22,16 @@ import isThenable from '#lib/is-thenable';
20
22
  *
21
23
  * @param {unknown} value
22
24
  * The thing to check
25
+ * @param {boolean | null | undefined} [finalizable=true]
26
+ * Whether a `finally` method is required.\
27
+ * When `false`, only `then` and `catch` are checked
23
28
  * @return {value is Promise<T>}
24
- * `true` if `value` is a thenable with a `catch` method, `false` otherwise
29
+ * `true` if `value` is a thenable with a `catch` method,
30
+ * and `finally` method (if requested), `false` otherwise
25
31
  */
26
- function isPromise(value) {
27
- if (!isThenable(value))
32
+ function isPromise(value, finalizable) {
33
+ if (!(isThenable(value) && isCatchable(value)))
28
34
  return false;
29
- return 'catch' in value && typeof value.catch === 'function';
35
+ return finalizable ?? true ? isFinalizable(value) : true;
30
36
  }
31
37
  export default isPromise;