source: node_modules/@reduxjs/toolkit/src/createAsyncThunk.ts

Last change on this file was a762898, checked in by istevanoska <ilinastevanoska@…>, 5 months ago

Added visualizations

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