-
Notifications
You must be signed in to change notification settings - Fork 0
/
mod.ts
245 lines (228 loc) · 8.65 KB
/
mod.ts
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
import isPlainObject from "./helpers/isPlainObject.ts";
/** A Flux Standard action with optional payload and metadata properties. */
export interface FluxStandardAction<
Type extends string = string,
Payload = undefined,
Meta = undefined,
> {
/**
* The `type` of an action identifies to the consumer the nature of the action that has occurred.
* Two actions with the same `type` MUST be strictly equivalent (using `===`)
*/
type: Type;
/**
* The optional `payload` property MAY be any type of value.
* It represents the payload of the action.
* Any information about the action that is not the type or status of the action should be part of the `payload` field.
* By convention, if `error` is `true`, the `payload` SHOULD be an error object.
* This is akin to rejecting a promise with an error object.
*/
payload?: Payload;
/**
* The optional `error` property MAY be set to true if the action represents an error.
* An action whose `error` is true is analogous to a rejected Promise.
* By convention, the `payload` SHOULD be an error object.
* If `error` has any other value besides `true`, including `undefined`, the action MUST NOT be interpreted as an error.
*/
error?: boolean;
/**
* The optional `meta` property MAY be any type of value.
* It is intended for any extra information that is not part of the payload.
*/
meta?: Meta;
}
/** An extension of the Flux Standard action that represents an action containing an error as its payload. */
export interface ErrorFluxStandardAction<
Type extends string = string,
CustomError extends Error = Error,
Meta = undefined,
> extends FluxStandardAction<Type, CustomError, Meta> {
/** The required `error` property MUST be set to `true` if the action represents an error. */
error: true;
}
/** Alias for FluxStandardAction. */
export type FSA<
Type extends string = string,
Payload = undefined,
Meta = undefined,
> = FluxStandardAction<Type, Payload, Meta>;
/** Alias for ErrorFluxStandardAction. */
export type ErrorFSA<
CustomError extends Error = Error,
Meta = undefined,
Type extends string = string,
> = ErrorFluxStandardAction<Type, CustomError, Meta>;
/** A Flux Standard action with a required payload property. */
export interface FluxStandardActionWithPayload<
Type extends string = string,
Payload = undefined,
Meta = undefined,
> extends FluxStandardAction<Type, Payload, Meta> {
/**
* The required `payload` property MAY be any type of value.
* It represents the payload of the action.
* Any information about the action that is not the type or status of the action should be part of the `payload` field.
* By convention, if `error` is `true`, the `payload` SHOULD be an error object.
* This is akin to rejecting a promise with an error object.
*/
payload: Payload;
}
/** Alias for FSAWithPayload */
export type FSAWithPayload<
Type extends string = string,
Payload = undefined,
Meta = undefined,
> = FluxStandardActionWithPayload<Type, Payload, Meta>;
/** A Flux Standard action with a required metadata property. */
export interface FluxStandardActionWithMeta<
Type extends string = string,
Payload = undefined,
Meta = undefined,
> extends FluxStandardAction<Type, Payload, Meta> {
/**
* The required `meta` property MAY be any type of value.
* It is intended for any extra information that is not part of the payload.
*/
meta: Meta;
}
/** Alias for FluxStandardActionWithMeta */
export type FSAWithMeta<
Type extends string = string,
Payload = undefined,
Meta = undefined,
> = FluxStandardActionWithMeta<Type, Payload, Meta>;
/** A Flux Standard action with required payload and metadata properties. */
export type FluxStandardActionWithPayloadAndMeta<
Type extends string = string,
Payload = undefined,
Meta = undefined,
> =
& FluxStandardActionWithPayload<Type, Payload, Meta>
& FluxStandardActionWithMeta<Type, Payload, Meta>;
/** Alias for FluxStandardActionWithPayloadAndMeta */
export type FSAWithPayloadAndMeta<
Type extends string = string,
Payload = undefined,
Meta = undefined,
> = FluxStandardActionWithPayloadAndMeta<Type, Payload, Meta>;
/**
* A Flux Standard action with inferred requirements for the payload and metadata properties.
* The `payload` and `meta` properties will be required if the corresponding type argument
* if not the `undefined` type.
*/
export type FluxStandardActionAuto<
Type extends string = string,
Payload = undefined,
Meta = undefined,
> = Payload extends undefined
? (Meta extends undefined ? FluxStandardAction<Type, Payload, Meta>
: FluxStandardActionWithMeta<Type, Payload, Meta>)
: (Meta extends undefined ? FluxStandardActionWithPayload<Type, Payload, Meta>
: FluxStandardActionWithPayloadAndMeta<Type, Payload, Meta>);
/** Alias for FluxStandardActionAuto */
export type FSAAuto<
Type extends string = string,
Payload = undefined,
Meta = undefined,
> = FluxStandardActionAuto<Type, Payload, Meta>;
/** A Flux Standard Error Action with a required payload property. */
export type ErrorFluxStandardActionWithPayload<
Type extends string = string,
CustomError extends Error = Error,
Meta = undefined,
> =
& ErrorFluxStandardAction<Type, CustomError, Meta>
& FluxStandardActionWithPayload<Type, CustomError, Meta>;
/** Alias for ErrorFluxStandardActionWithPayload */
export type ErrorFSAWithPayload<
Type extends string = string,
CustomError extends Error = Error,
Meta = undefined,
> = ErrorFluxStandardActionWithPayload<Type, CustomError, Meta>;
/** A Flux Standard Error Action with a required metadata property. */
export type ErrorFluxStandardActionWithMeta<
Type extends string = string,
CustomError extends Error = Error,
Meta = undefined,
> =
& ErrorFluxStandardAction<Type, CustomError, Meta>
& FluxStandardActionWithMeta<Type, CustomError, Meta>;
/** Alias for ErrorFluxStandardActionWithMeta */
export type ErrorFSAWithMeta<
Type extends string = string,
CustomError extends Error = Error,
Meta = undefined,
> = ErrorFluxStandardActionWithMeta<Type, CustomError, Meta>;
/** A Flux Standard Error Action with required payload and metadata properties. */
export type ErrorFluxStandardActionWithPayloadAndMeta<
Type extends string = string,
CustomError extends Error = Error,
Meta = undefined,
> =
& ErrorFluxStandardActionWithPayload<Type, CustomError, Meta>
& ErrorFluxStandardActionWithMeta<Type, CustomError, Meta>;
/** Alias for ErrorFluxStandardActionWithPayloadAndMeta */
export type ErrorFSAWithPayloadAndMeta<
Type extends string = string,
CustomError extends Error = Error,
Meta = undefined,
> = ErrorFluxStandardActionWithPayloadAndMeta<Type, CustomError, Meta>;
/**
* A Flux Standard Error action with inferred requirements for the payload and metadata properties.
* The `payload` and `meta` properties will be required if the corresponding type argument
* if not the `undefined` type.
*
* Note: The `payload` property will always be required, since the `CustomError` type argument does
* not allow for specification of the `undefined` type.
*/
export type ErrorFluxStandardActionAuto<
Type extends string = string,
CustomError extends Error = Error,
Meta = undefined,
> = Meta extends undefined
? ErrorFluxStandardActionWithPayload<Type, CustomError, Meta>
: ErrorFluxStandardActionWithPayloadAndMeta<Type, CustomError, Meta>;
/** Alias for ErrorFluxStandardActionAuto */
export type ErrorFSAAuto<
Type extends string = string,
CustomError extends Error = Error,
Meta = undefined,
> = ErrorFluxStandardActionAuto<Type, CustomError, Meta>;
const allowedKeys = ["type", "payload", "error", "meta"];
function isValidKey(key: string): boolean {
return allowedKeys.includes(key);
}
function hasTypeProperty<T extends Object = Object>(
params: T,
): params is T & { type: unknown } {
return Object.prototype.hasOwnProperty.call(params, "type");
}
/**
* Checks if `action` is FSA compliant.
* @param {unknown} action any object to check.
* @returns {boolean} `true` if `action` is FSA compliant.
*/
export function isFSA<
Type extends string = string,
Payload = undefined,
Meta = undefined,
>(action: unknown): action is FluxStandardAction<Type, Payload, Meta> {
return (
isPlainObject(action) &&
hasTypeProperty(action) &&
typeof action.type === "string" &&
Object.keys(action).every(isValidKey)
);
}
/**
* Checks if `action` is FSA compliant error.
* @param {unknown} action any object to check.
* @returns {boolean} `true` if `action` is FSA compliant error.
*/
export function isError<
Type extends string = string,
CustomError extends Error = Error,
Meta = undefined,
>(action: unknown): action is ErrorFluxStandardAction<Type, CustomError, Meta> {
return isFSA(action) && action.error === true;
}