-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathcreate-async-action.ts
More file actions
103 lines (97 loc) · 3.95 KB
/
Copy pathcreate-async-action.ts
File metadata and controls
103 lines (97 loc) · 3.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// biome-ignore-all lint/suspicious/noExplicitAny: generic constraints mirror create-action.ts's ported redux-toolkit PrepareAction<any> dispatch pattern
import { actionSuffixDivider, createAction } from './create-action.js';
import {
isActionWithSuffix,
isCompleteAction,
isFailureAction,
isRequestAction,
isSuccessAction,
} from './predicates.js';
import type { PayloadActionCreator } from './create-action.js';
import type { PrepareAction } from './create-action.js';
/**
* Creates an async action creator that produces request, success, and optionally failure sub-actions.
*
* The returned action creator dispatches a `request` action (suffixed with `::request`),
* and has `.success` (suffixed with `::success`) and optionally `.failure` (suffixed with `::failure`)
* action creator properties attached.
*
* @param type - The base action type string.
* @param request - A prepare function for the `request` action payload.
* @param success - A prepare function for the `success` action payload.
* @returns An action creator for requests, with a `.success` property.
*
* @example
* ```ts
* import { createAsyncAction } from '@equinor/fusion-observable';
*
* const fetchUser = createAsyncAction(
* 'fetchUser',
* (id: string) => ({ payload: { id } }),
* (user: User) => ({ payload: user }),
* );
*
* dispatch(fetchUser('abc')); // { type: 'fetchUser::request', payload: { id: 'abc' } }
* dispatch(fetchUser.success(userData)); // { type: 'fetchUser::success', payload: userData }
* ```
*/
export function createAsyncAction<
PA extends PrepareAction<any>,
PA_Success extends PrepareAction<any>,
T extends string,
>(
type: T,
request: PA,
success: PA_Success,
): PayloadActionCreator<ReturnType<PA>['payload'], `${T}::request`, PA> & {
success: PayloadActionCreator<ReturnType<PA_Success>['payload'], `${T}::success`, PA_Success>;
};
export function createAsyncAction<
PA extends PrepareAction<any>,
PA_Success extends PrepareAction<any>,
PA_Failure extends PrepareAction<any>,
T extends string,
>(
type: T,
request: PA,
success: PA_Success,
failure: PA_Failure,
): PayloadActionCreator<ReturnType<PA>['payload'], `${T}::request`, PA> & {
success: PayloadActionCreator<ReturnType<PA_Success>['payload'], `${T}::success`, PA_Success>;
failure: PayloadActionCreator<ReturnType<PA_Failure>['payload'], `${T}::failure`, PA_Failure>;
};
/**
* Creates the runtime async action implementation shared by the overloads above.
*
* @param type - The base action type string.
* @param request - A prepare function for the request action payload.
* @param success - A prepare function for the success action payload.
* @param failure - An optional prepare function for the failure action payload.
* @returns An action creator with request, success, and optional failure actions.
*/
export function createAsyncAction(
type: string,
request: PrepareAction<any>,
success: PrepareAction<any>,
failure?: PrepareAction<any>,
): any {
const action = createAction([type, 'request'].join(actionSuffixDivider), request);
// Attach the success action only when the caller supplied its prepare function.
if (success) {
// Add the success action while preserving the request creator's identity.
Object.assign(action, {
success: createAction([type, 'success'].join(actionSuffixDivider), success),
});
}
// Attach the failure action only for async workflows that support failure results.
if (failure) {
// Add the failure action alongside the existing request and success actions.
Object.assign(action, {
failure: createAction([type, 'failure'].join(actionSuffixDivider), failure),
});
}
// `action` is progressively mutated with `success`/`failure` properties above, so its static
// type can't reflect the final shape declared by this function's overload signatures.
return action as unknown as any;
}
export { isActionWithSuffix, isCompleteAction, isFailureAction, isRequestAction, isSuccessAction };