1 | import type { Dispatch, UnknownAction } from 'redux'
|
2 | import type {
|
3 | PayloadAction,
|
4 | ActionCreatorWithPreparedPayload,
|
5 | } from './createAction'
|
6 | import { createAction } from './createAction'
|
7 | import type { ThunkDispatch } from 'redux-thunk'
|
8 | import type {
|
9 | ActionFromMatcher,
|
10 | FallbackIfUnknown,
|
11 | Id,
|
12 | IsAny,
|
13 | IsUnknown,
|
14 | SafePromise,
|
15 | TypeGuard,
|
16 | } from './tsHelpers'
|
17 | import { nanoid } from './nanoid'
|
18 | import { isAnyOf } from './matchers'
|
19 |
|
20 |
|
21 | type _Keep = PayloadAction | ActionCreatorWithPreparedPayload<any, unknown>
|
22 |
|
23 | export type BaseThunkAPI<
|
24 | S,
|
25 | E,
|
26 | D extends Dispatch = Dispatch,
|
27 | RejectedValue = unknown,
|
28 | RejectedMeta = unknown,
|
29 | FulfilledMeta = unknown,
|
30 | > = {
|
31 | dispatch: D
|
32 | getState: () => S
|
33 | extra: E
|
34 | requestId: string
|
35 | signal: AbortSignal
|
36 | abort: (reason?: string) => void
|
37 | rejectWithValue: IsUnknown<
|
38 | RejectedMeta,
|
39 | (value: RejectedValue) => RejectWithValue<RejectedValue, RejectedMeta>,
|
40 | (
|
41 | value: RejectedValue,
|
42 | meta: RejectedMeta,
|
43 | ) => RejectWithValue<RejectedValue, RejectedMeta>
|
44 | >
|
45 | fulfillWithValue: IsUnknown<
|
46 | FulfilledMeta,
|
47 | <FulfilledValue>(value: FulfilledValue) => FulfilledValue,
|
48 | <FulfilledValue>(
|
49 | value: FulfilledValue,
|
50 | meta: FulfilledMeta,
|
51 | ) => FulfillWithMeta<FulfilledValue, FulfilledMeta>
|
52 | >
|
53 | }
|
54 |
|
55 |
|
56 |
|
57 |
|
58 | export interface SerializedError {
|
59 | name?: string
|
60 | message?: string
|
61 | stack?: string
|
62 | code?: string
|
63 | }
|
64 |
|
65 | const commonProperties: Array<keyof SerializedError> = [
|
66 | 'name',
|
67 | 'message',
|
68 | 'stack',
|
69 | 'code',
|
70 | ]
|
71 |
|
72 | class RejectWithValue<Payload, RejectedMeta> {
|
73 | |
74 |
|
75 |
|
76 |
|
77 | private readonly _type!: 'RejectWithValue'
|
78 | constructor(
|
79 | public readonly payload: Payload,
|
80 | public readonly meta: RejectedMeta,
|
81 | ) {}
|
82 | }
|
83 |
|
84 | class FulfillWithMeta<Payload, FulfilledMeta> {
|
85 | |
86 |
|
87 |
|
88 |
|
89 | private readonly _type!: 'FulfillWithMeta'
|
90 | constructor(
|
91 | public readonly payload: Payload,
|
92 | public readonly meta: FulfilledMeta,
|
93 | ) {}
|
94 | }
|
95 |
|
96 |
|
97 |
|
98 |
|
99 |
|
100 |
|
101 |
|
102 | export const miniSerializeError = (value: any): SerializedError => {
|
103 | if (typeof value === 'object' && value !== null) {
|
104 | const simpleError: SerializedError = {}
|
105 | for (const property of commonProperties) {
|
106 | if (typeof value[property] === 'string') {
|
107 | simpleError[property] = value[property]
|
108 | }
|
109 | }
|
110 |
|
111 | return simpleError
|
112 | }
|
113 |
|
114 | return { message: String(value) }
|
115 | }
|
116 |
|
117 | export type AsyncThunkConfig = {
|
118 | state?: unknown
|
119 | dispatch?: ThunkDispatch<unknown, unknown, UnknownAction>
|
120 | extra?: unknown
|
121 | rejectValue?: unknown
|
122 | serializedErrorType?: unknown
|
123 | pendingMeta?: unknown
|
124 | fulfilledMeta?: unknown
|
125 | rejectedMeta?: unknown
|
126 | }
|
127 |
|
128 | type GetState<ThunkApiConfig> = ThunkApiConfig extends {
|
129 | state: infer State
|
130 | }
|
131 | ? State
|
132 | : unknown
|
133 | type GetExtra<ThunkApiConfig> = ThunkApiConfig extends { extra: infer Extra }
|
134 | ? Extra
|
135 | : unknown
|
136 | type GetDispatch<ThunkApiConfig> = ThunkApiConfig extends {
|
137 | dispatch: infer Dispatch
|
138 | }
|
139 | ? FallbackIfUnknown<
|
140 | Dispatch,
|
141 | ThunkDispatch<
|
142 | GetState<ThunkApiConfig>,
|
143 | GetExtra<ThunkApiConfig>,
|
144 | UnknownAction
|
145 | >
|
146 | >
|
147 | : ThunkDispatch<
|
148 | GetState<ThunkApiConfig>,
|
149 | GetExtra<ThunkApiConfig>,
|
150 | UnknownAction
|
151 | >
|
152 |
|
153 | export type GetThunkAPI<ThunkApiConfig> = BaseThunkAPI<
|
154 | GetState<ThunkApiConfig>,
|
155 | GetExtra<ThunkApiConfig>,
|
156 | GetDispatch<ThunkApiConfig>,
|
157 | GetRejectValue<ThunkApiConfig>,
|
158 | GetRejectedMeta<ThunkApiConfig>,
|
159 | GetFulfilledMeta<ThunkApiConfig>
|
160 | >
|
161 |
|
162 | type GetRejectValue<ThunkApiConfig> = ThunkApiConfig extends {
|
163 | rejectValue: infer RejectValue
|
164 | }
|
165 | ? RejectValue
|
166 | : unknown
|
167 |
|
168 | type GetPendingMeta<ThunkApiConfig> = ThunkApiConfig extends {
|
169 | pendingMeta: infer PendingMeta
|
170 | }
|
171 | ? PendingMeta
|
172 | : unknown
|
173 |
|
174 | type GetFulfilledMeta<ThunkApiConfig> = ThunkApiConfig extends {
|
175 | fulfilledMeta: infer FulfilledMeta
|
176 | }
|
177 | ? FulfilledMeta
|
178 | : unknown
|
179 |
|
180 | type GetRejectedMeta<ThunkApiConfig> = ThunkApiConfig extends {
|
181 | rejectedMeta: infer RejectedMeta
|
182 | }
|
183 | ? RejectedMeta
|
184 | : unknown
|
185 |
|
186 | type GetSerializedErrorType<ThunkApiConfig> = ThunkApiConfig extends {
|
187 | serializedErrorType: infer GetSerializedErrorType
|
188 | }
|
189 | ? GetSerializedErrorType
|
190 | : SerializedError
|
191 |
|
192 | type MaybePromise<T> = T | Promise<T> | (T extends any ? Promise<T> : never)
|
193 |
|
194 |
|
195 |
|
196 |
|
197 |
|
198 |
|
199 |
|
200 | export type AsyncThunkPayloadCreatorReturnValue<
|
201 | Returned,
|
202 | ThunkApiConfig extends AsyncThunkConfig,
|
203 | > = MaybePromise<
|
204 | | IsUnknown<
|
205 | GetFulfilledMeta<ThunkApiConfig>,
|
206 | Returned,
|
207 | FulfillWithMeta<Returned, GetFulfilledMeta<ThunkApiConfig>>
|
208 | >
|
209 | | RejectWithValue<
|
210 | GetRejectValue<ThunkApiConfig>,
|
211 | GetRejectedMeta<ThunkApiConfig>
|
212 | >
|
213 | >
|
214 |
|
215 |
|
216 |
|
217 |
|
218 |
|
219 |
|
220 | export type AsyncThunkPayloadCreator<
|
221 | Returned,
|
222 | ThunkArg = void,
|
223 | ThunkApiConfig extends AsyncThunkConfig = {},
|
224 | > = (
|
225 | arg: ThunkArg,
|
226 | thunkAPI: GetThunkAPI<ThunkApiConfig>,
|
227 | ) => AsyncThunkPayloadCreatorReturnValue<Returned, ThunkApiConfig>
|
228 |
|
229 |
|
230 |
|
231 |
|
232 |
|
233 |
|
234 |
|
235 |
|
236 |
|
237 |
|
238 | export type AsyncThunkAction<
|
239 | Returned,
|
240 | ThunkArg,
|
241 | ThunkApiConfig extends AsyncThunkConfig,
|
242 | > = (
|
243 | dispatch: NonNullable<GetDispatch<ThunkApiConfig>>,
|
244 | getState: () => GetState<ThunkApiConfig>,
|
245 | extra: GetExtra<ThunkApiConfig>,
|
246 | ) => SafePromise<
|
247 | | ReturnType<AsyncThunkFulfilledActionCreator<Returned, ThunkArg>>
|
248 | | ReturnType<AsyncThunkRejectedActionCreator<ThunkArg, ThunkApiConfig>>
|
249 | > & {
|
250 | abort: (reason?: string) => void
|
251 | requestId: string
|
252 | arg: ThunkArg
|
253 | unwrap: () => Promise<Returned>
|
254 | }
|
255 |
|
256 | type AsyncThunkActionCreator<
|
257 | Returned,
|
258 | ThunkArg,
|
259 | ThunkApiConfig extends AsyncThunkConfig,
|
260 | > = IsAny<
|
261 | ThunkArg,
|
262 |
|
263 | (arg: ThunkArg) => AsyncThunkAction<Returned, ThunkArg, ThunkApiConfig>,
|
264 |
|
265 | unknown extends ThunkArg
|
266 | ? (arg: ThunkArg) => AsyncThunkAction<Returned, ThunkArg, ThunkApiConfig>
|
267 | : [ThunkArg] extends [void] | [undefined]
|
268 | ? () => AsyncThunkAction<Returned, ThunkArg, ThunkApiConfig>
|
269 | : [void] extends [ThunkArg]
|
270 | ? (
|
271 | arg?: ThunkArg,
|
272 | ) => AsyncThunkAction<Returned, ThunkArg, ThunkApiConfig>
|
273 | : [undefined] extends [ThunkArg]
|
274 | ? WithStrictNullChecks<
|
275 |
|
276 | (
|
277 | arg?: ThunkArg,
|
278 | ) => AsyncThunkAction<Returned, ThunkArg, ThunkApiConfig>,
|
279 |
|
280 | (
|
281 | arg: ThunkArg,
|
282 | ) => AsyncThunkAction<Returned, ThunkArg, ThunkApiConfig>
|
283 | >
|
284 | : (
|
285 | arg: ThunkArg,
|
286 | ) => AsyncThunkAction<Returned, ThunkArg, ThunkApiConfig>
|
287 | >
|
288 |
|
289 |
|
290 |
|
291 |
|
292 |
|
293 |
|
294 | export type AsyncThunkOptions<
|
295 | ThunkArg = void,
|
296 | ThunkApiConfig extends AsyncThunkConfig = {},
|
297 | > = {
|
298 | |
299 |
|
300 |
|
301 |
|
302 |
|
303 |
|
304 | condition?(
|
305 | arg: ThunkArg,
|
306 | api: Pick<GetThunkAPI<ThunkApiConfig>, 'getState' | 'extra'>,
|
307 | ): MaybePromise<boolean | undefined>
|
308 | |
309 |
|
310 |
|
311 |
|
312 |
|
313 |
|
314 |
|
315 | dispatchConditionRejection?: boolean
|
316 |
|
317 | serializeError?: (x: unknown) => GetSerializedErrorType<ThunkApiConfig>
|
318 |
|
319 | |
320 |
|
321 |
|
322 |
|
323 |
|
324 | idGenerator?: (arg: ThunkArg) => string
|
325 | } & IsUnknown<
|
326 | GetPendingMeta<ThunkApiConfig>,
|
327 | {
|
328 | |
329 |
|
330 |
|
331 |
|
332 |
|
333 |
|
334 | getPendingMeta?(
|
335 | base: {
|
336 | arg: ThunkArg
|
337 | requestId: string
|
338 | },
|
339 | api: Pick<GetThunkAPI<ThunkApiConfig>, 'getState' | 'extra'>,
|
340 | ): GetPendingMeta<ThunkApiConfig>
|
341 | },
|
342 | {
|
343 | |
344 |
|
345 |
|
346 | getPendingMeta(
|
347 | base: {
|
348 | arg: ThunkArg
|
349 | requestId: string
|
350 | },
|
351 | api: Pick<GetThunkAPI<ThunkApiConfig>, 'getState' | 'extra'>,
|
352 | ): GetPendingMeta<ThunkApiConfig>
|
353 | }
|
354 | >
|
355 |
|
356 | export type AsyncThunkPendingActionCreator<
|
357 | ThunkArg,
|
358 | ThunkApiConfig = {},
|
359 | > = ActionCreatorWithPreparedPayload<
|
360 | [string, ThunkArg, GetPendingMeta<ThunkApiConfig>?],
|
361 | undefined,
|
362 | string,
|
363 | never,
|
364 | {
|
365 | arg: ThunkArg
|
366 | requestId: string
|
367 | requestStatus: 'pending'
|
368 | } & GetPendingMeta<ThunkApiConfig>
|
369 | >
|
370 |
|
371 | export type AsyncThunkRejectedActionCreator<
|
372 | ThunkArg,
|
373 | ThunkApiConfig = {},
|
374 | > = ActionCreatorWithPreparedPayload<
|
375 | [
|
376 | Error | null,
|
377 | string,
|
378 | ThunkArg,
|
379 | GetRejectValue<ThunkApiConfig>?,
|
380 | GetRejectedMeta<ThunkApiConfig>?,
|
381 | ],
|
382 | GetRejectValue<ThunkApiConfig> | undefined,
|
383 | string,
|
384 | GetSerializedErrorType<ThunkApiConfig>,
|
385 | {
|
386 | arg: ThunkArg
|
387 | requestId: string
|
388 | requestStatus: 'rejected'
|
389 | aborted: boolean
|
390 | condition: boolean
|
391 | } & (
|
392 | | ({ rejectedWithValue: false } & {
|
393 | [K in keyof GetRejectedMeta<ThunkApiConfig>]?: undefined
|
394 | })
|
395 | | ({ rejectedWithValue: true } & GetRejectedMeta<ThunkApiConfig>)
|
396 | )
|
397 | >
|
398 |
|
399 | export type AsyncThunkFulfilledActionCreator<
|
400 | Returned,
|
401 | ThunkArg,
|
402 | ThunkApiConfig = {},
|
403 | > = ActionCreatorWithPreparedPayload<
|
404 | [Returned, string, ThunkArg, GetFulfilledMeta<ThunkApiConfig>?],
|
405 | Returned,
|
406 | string,
|
407 | never,
|
408 | {
|
409 | arg: ThunkArg
|
410 | requestId: string
|
411 | requestStatus: 'fulfilled'
|
412 | } & GetFulfilledMeta<ThunkApiConfig>
|
413 | >
|
414 |
|
415 |
|
416 |
|
417 |
|
418 |
|
419 |
|
420 |
|
421 | export type AsyncThunk<
|
422 | Returned,
|
423 | ThunkArg,
|
424 | ThunkApiConfig extends AsyncThunkConfig,
|
425 | > = AsyncThunkActionCreator<Returned, ThunkArg, ThunkApiConfig> & {
|
426 | pending: AsyncThunkPendingActionCreator<ThunkArg, ThunkApiConfig>
|
427 | rejected: AsyncThunkRejectedActionCreator<ThunkArg, ThunkApiConfig>
|
428 | fulfilled: AsyncThunkFulfilledActionCreator<
|
429 | Returned,
|
430 | ThunkArg,
|
431 | ThunkApiConfig
|
432 | >
|
433 |
|
434 | settled: (
|
435 | action: any,
|
436 | ) => action is ReturnType<
|
437 | | AsyncThunkRejectedActionCreator<ThunkArg, ThunkApiConfig>
|
438 | | AsyncThunkFulfilledActionCreator<Returned, ThunkArg, ThunkApiConfig>
|
439 | >
|
440 | typePrefix: string
|
441 | }
|
442 |
|
443 | export type OverrideThunkApiConfigs<OldConfig, NewConfig> = Id<
|
444 | NewConfig & Omit<OldConfig, keyof NewConfig>
|
445 | >
|
446 |
|
447 | type CreateAsyncThunk<CurriedThunkApiConfig extends AsyncThunkConfig> = {
|
448 | |
449 |
|
450 |
|
451 |
|
452 |
|
453 |
|
454 |
|
455 |
|
456 |
|
457 | <Returned, ThunkArg = void>(
|
458 | typePrefix: string,
|
459 | payloadCreator: AsyncThunkPayloadCreator<
|
460 | Returned,
|
461 | ThunkArg,
|
462 | CurriedThunkApiConfig
|
463 | >,
|
464 | options?: AsyncThunkOptions<ThunkArg, CurriedThunkApiConfig>,
|
465 | ): AsyncThunk<Returned, ThunkArg, CurriedThunkApiConfig>
|
466 |
|
467 | |
468 |
|
469 |
|
470 |
|
471 |
|
472 |
|
473 |
|
474 |
|
475 | <Returned, ThunkArg, ThunkApiConfig extends AsyncThunkConfig>(
|
476 | typePrefix: string,
|
477 | payloadCreator: AsyncThunkPayloadCreator<
|
478 | Returned,
|
479 | ThunkArg,
|
480 | OverrideThunkApiConfigs<CurriedThunkApiConfig, ThunkApiConfig>
|
481 | >,
|
482 | options?: AsyncThunkOptions<
|
483 | ThunkArg,
|
484 | OverrideThunkApiConfigs<CurriedThunkApiConfig, ThunkApiConfig>
|
485 | >,
|
486 | ): AsyncThunk<
|
487 | Returned,
|
488 | ThunkArg,
|
489 | OverrideThunkApiConfigs<CurriedThunkApiConfig, ThunkApiConfig>
|
490 | >
|
491 |
|
492 | withTypes<ThunkApiConfig extends AsyncThunkConfig>(): CreateAsyncThunk<
|
493 | OverrideThunkApiConfigs<CurriedThunkApiConfig, ThunkApiConfig>
|
494 | >
|
495 | }
|
496 |
|
497 | export const createAsyncThunk = (() => {
|
498 | function createAsyncThunk<
|
499 | Returned,
|
500 | ThunkArg,
|
501 | ThunkApiConfig extends AsyncThunkConfig,
|
502 | >(
|
503 | typePrefix: string,
|
504 | payloadCreator: AsyncThunkPayloadCreator<
|
505 | Returned,
|
506 | ThunkArg,
|
507 | ThunkApiConfig
|
508 | >,
|
509 | options?: AsyncThunkOptions<ThunkArg, ThunkApiConfig>,
|
510 | ): AsyncThunk<Returned, ThunkArg, ThunkApiConfig> {
|
511 | type RejectedValue = GetRejectValue<ThunkApiConfig>
|
512 | type PendingMeta = GetPendingMeta<ThunkApiConfig>
|
513 | type FulfilledMeta = GetFulfilledMeta<ThunkApiConfig>
|
514 | type RejectedMeta = GetRejectedMeta<ThunkApiConfig>
|
515 |
|
516 | const fulfilled: AsyncThunkFulfilledActionCreator<
|
517 | Returned,
|
518 | ThunkArg,
|
519 | ThunkApiConfig
|
520 | > = createAction(
|
521 | typePrefix + '/fulfilled',
|
522 | (
|
523 | payload: Returned,
|
524 | requestId: string,
|
525 | arg: ThunkArg,
|
526 | meta?: FulfilledMeta,
|
527 | ) => ({
|
528 | payload,
|
529 | meta: {
|
530 | ...((meta as any) || {}),
|
531 | arg,
|
532 | requestId,
|
533 | requestStatus: 'fulfilled' as const,
|
534 | },
|
535 | }),
|
536 | )
|
537 |
|
538 | const pending: AsyncThunkPendingActionCreator<ThunkArg, ThunkApiConfig> =
|
539 | createAction(
|
540 | typePrefix + '/pending',
|
541 | (requestId: string, arg: ThunkArg, meta?: PendingMeta) => ({
|
542 | payload: undefined,
|
543 | meta: {
|
544 | ...((meta as any) || {}),
|
545 | arg,
|
546 | requestId,
|
547 | requestStatus: 'pending' as const,
|
548 | },
|
549 | }),
|
550 | )
|
551 |
|
552 | const rejected: AsyncThunkRejectedActionCreator<ThunkArg, ThunkApiConfig> =
|
553 | createAction(
|
554 | typePrefix + '/rejected',
|
555 | (
|
556 | error: Error | null,
|
557 | requestId: string,
|
558 | arg: ThunkArg,
|
559 | payload?: RejectedValue,
|
560 | meta?: RejectedMeta,
|
561 | ) => ({
|
562 | payload,
|
563 | error: ((options && options.serializeError) || miniSerializeError)(
|
564 | error || 'Rejected',
|
565 | ) as GetSerializedErrorType<ThunkApiConfig>,
|
566 | meta: {
|
567 | ...((meta as any) || {}),
|
568 | arg,
|
569 | requestId,
|
570 | rejectedWithValue: !!payload,
|
571 | requestStatus: 'rejected' as const,
|
572 | aborted: error?.name === 'AbortError',
|
573 | condition: error?.name === 'ConditionError',
|
574 | },
|
575 | }),
|
576 | )
|
577 |
|
578 | function actionCreator(
|
579 | arg: ThunkArg,
|
580 | ): AsyncThunkAction<Returned, ThunkArg, Required<ThunkApiConfig>> {
|
581 | return (dispatch, getState, extra) => {
|
582 | const requestId = options?.idGenerator
|
583 | ? options.idGenerator(arg)
|
584 | : nanoid()
|
585 |
|
586 | const abortController = new AbortController()
|
587 | let abortHandler: (() => void) | undefined
|
588 | let abortReason: string | undefined
|
589 |
|
590 | function abort(reason?: string) {
|
591 | abortReason = reason
|
592 | abortController.abort()
|
593 | }
|
594 |
|
595 | const promise = (async function () {
|
596 | let finalAction: ReturnType<typeof fulfilled | typeof rejected>
|
597 | try {
|
598 | let conditionResult = options?.condition?.(arg, { getState, extra })
|
599 | if (isThenable(conditionResult)) {
|
600 | conditionResult = await conditionResult
|
601 | }
|
602 |
|
603 | if (conditionResult === false || abortController.signal.aborted) {
|
604 |
|
605 | throw {
|
606 | name: 'ConditionError',
|
607 | message: 'Aborted due to condition callback returning false.',
|
608 | }
|
609 | }
|
610 |
|
611 | const abortedPromise = new Promise<never>((_, reject) => {
|
612 | abortHandler = () => {
|
613 | reject({
|
614 | name: 'AbortError',
|
615 | message: abortReason || 'Aborted',
|
616 | })
|
617 | }
|
618 | abortController.signal.addEventListener('abort', abortHandler)
|
619 | })
|
620 | dispatch(
|
621 | pending(
|
622 | requestId,
|
623 | arg,
|
624 | options?.getPendingMeta?.(
|
625 | { requestId, arg },
|
626 | { getState, extra },
|
627 | ),
|
628 | ) as any,
|
629 | )
|
630 | finalAction = await Promise.race([
|
631 | abortedPromise,
|
632 | Promise.resolve(
|
633 | payloadCreator(arg, {
|
634 | dispatch,
|
635 | getState,
|
636 | extra,
|
637 | requestId,
|
638 | signal: abortController.signal,
|
639 | abort,
|
640 | rejectWithValue: ((
|
641 | value: RejectedValue,
|
642 | meta?: RejectedMeta,
|
643 | ) => {
|
644 | return new RejectWithValue(value, meta)
|
645 | }) as any,
|
646 | fulfillWithValue: ((value: unknown, meta?: FulfilledMeta) => {
|
647 | return new FulfillWithMeta(value, meta)
|
648 | }) as any,
|
649 | }),
|
650 | ).then((result) => {
|
651 | if (result instanceof RejectWithValue) {
|
652 | throw result
|
653 | }
|
654 | if (result instanceof FulfillWithMeta) {
|
655 | return fulfilled(result.payload, requestId, arg, result.meta)
|
656 | }
|
657 | return fulfilled(result as any, requestId, arg)
|
658 | }),
|
659 | ])
|
660 | } catch (err) {
|
661 | finalAction =
|
662 | err instanceof RejectWithValue
|
663 | ? rejected(null, requestId, arg, err.payload, err.meta)
|
664 | : rejected(err as any, requestId, arg)
|
665 | } finally {
|
666 | if (abortHandler) {
|
667 | abortController.signal.removeEventListener('abort', abortHandler)
|
668 | }
|
669 | }
|
670 |
|
671 |
|
672 |
|
673 |
|
674 |
|
675 | const skipDispatch =
|
676 | options &&
|
677 | !options.dispatchConditionRejection &&
|
678 | rejected.match(finalAction) &&
|
679 | (finalAction as any).meta.condition
|
680 |
|
681 | if (!skipDispatch) {
|
682 | dispatch(finalAction as any)
|
683 | }
|
684 | return finalAction
|
685 | })()
|
686 | return Object.assign(promise as SafePromise<any>, {
|
687 | abort,
|
688 | requestId,
|
689 | arg,
|
690 | unwrap() {
|
691 | return promise.then<any>(unwrapResult)
|
692 | },
|
693 | })
|
694 | }
|
695 | }
|
696 |
|
697 | return Object.assign(
|
698 | actionCreator as AsyncThunkActionCreator<
|
699 | Returned,
|
700 | ThunkArg,
|
701 | ThunkApiConfig
|
702 | >,
|
703 | {
|
704 | pending,
|
705 | rejected,
|
706 | fulfilled,
|
707 | settled: isAnyOf(rejected, fulfilled),
|
708 | typePrefix,
|
709 | },
|
710 | )
|
711 | }
|
712 | createAsyncThunk.withTypes = () => createAsyncThunk
|
713 |
|
714 | return createAsyncThunk as CreateAsyncThunk<AsyncThunkConfig>
|
715 | })()
|
716 |
|
717 | interface UnwrappableAction {
|
718 | payload: any
|
719 | meta?: any
|
720 | error?: any
|
721 | }
|
722 |
|
723 | type UnwrappedActionPayload<T extends UnwrappableAction> = Exclude<
|
724 | T,
|
725 | { error: any }
|
726 | >['payload']
|
727 |
|
728 |
|
729 |
|
730 |
|
731 | export function unwrapResult<R extends UnwrappableAction>(
|
732 | action: R,
|
733 | ): UnwrappedActionPayload<R> {
|
734 | if (action.meta && action.meta.rejectedWithValue) {
|
735 | throw action.payload
|
736 | }
|
737 | if (action.error) {
|
738 | throw action.error
|
739 | }
|
740 | return action.payload
|
741 | }
|
742 |
|
743 | type WithStrictNullChecks<True, False> = undefined extends boolean
|
744 | ? False
|
745 | : True
|
746 |
|
747 | function isThenable(value: any): value is PromiseLike<any> {
|
748 | return (
|
749 | value !== null &&
|
750 | typeof value === 'object' &&
|
751 | typeof value.then === 'function'
|
752 | )
|
753 | }
|