@nlozgachev/pipelined 0.36.0 → 0.37.1
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/README.md +18 -7
- package/dist/{Task-DXsuurnc.d.mts → Task-DcXhCZYg.d.mts} +472 -380
- package/dist/{Task-zAY4kSVB.d.ts → Task-uupX7xd9.d.ts} +472 -380
- package/dist/{chunk-VWVPHDZO.mjs → chunk-5AFEEFE4.mjs} +5 -1
- package/dist/{chunk-IJFFWBKW.mjs → chunk-E7YI5PVW.mjs} +2 -2
- package/dist/{chunk-4QMYKCWE.mjs → chunk-M2X7TFKN.mjs} +500 -100
- package/dist/core.d.mts +743 -605
- package/dist/core.d.ts +743 -605
- package/dist/core.js +336 -246
- package/dist/core.mjs +6 -8
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +353 -263
- package/dist/index.mjs +16 -21
- package/dist/types.d.mts +29 -29
- package/dist/types.d.ts +29 -29
- package/dist/types.mjs +3 -6
- package/dist/utils.d.mts +1 -1
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +89 -51
- package/dist/utils.mjs +3 -4
- package/package.json +17 -5
- package/dist/chunk-DBIC62UV.mjs +0 -6
- package/dist/chunk-DLBHVYII.mjs +0 -322
- package/dist/chunk-IPP4XFYH.mjs +0 -0
package/dist/core.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { M as Maybe,
|
|
2
|
-
export { E as Equality, a as Err, N as None, O as Ok, b as Ordering, S as Some } from './Task-
|
|
1
|
+
import { M as Maybe, q as WithValue, k as WithLog, D as Deferred, R as Result, j as WithKind, g as WithError, c as RetryOptions, d as TimeoutOptions, p as WithTimeout, l as WithMinInterval, e as WithCooldown, W as WithConcurrency, o as WithSize, f as WithDuration, m as WithN, T as Task, i as WithFirst, n as WithSecond, h as WithErrors } from './Task-DcXhCZYg.mjs';
|
|
2
|
+
export { E as Equality, a as Err, N as None, O as Ok, b as Ordering, S as Some } from './Task-DcXhCZYg.mjs';
|
|
3
3
|
import { Duration, NonEmptyList } from './types.mjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -166,161 +166,6 @@ declare namespace Lazy {
|
|
|
166
166
|
const tap: <A>(f: (a: A) => void) => (lazy: Lazy<A>) => Lazy<A>;
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
-
/** Keys of T for which undefined is assignable (i.e. optional fields). */
|
|
170
|
-
type OptionalKeys<T> = {
|
|
171
|
-
[K in keyof T]-?: undefined extends T[K] ? K : never;
|
|
172
|
-
}[keyof T];
|
|
173
|
-
/**
|
|
174
|
-
* Optional<S, A> focuses on a value A inside a structure S that may or may
|
|
175
|
-
* not be present. Like a Lens, but get returns Maybe<A>.
|
|
176
|
-
*
|
|
177
|
-
* Compose with other Optionals via `andThen`, or with a Lens via `andThenLens`.
|
|
178
|
-
* Convert a Lens to an Optional with `Lens.toOptional`.
|
|
179
|
-
*
|
|
180
|
-
* @example
|
|
181
|
-
* ```ts
|
|
182
|
-
* type Profile = { username: string; bio?: string };
|
|
183
|
-
*
|
|
184
|
-
* const bioOpt = Optional.prop<Profile>()("bio");
|
|
185
|
-
*
|
|
186
|
-
* pipe(profile, Optional.get(bioOpt)); // Some("hello") or None
|
|
187
|
-
* pipe(profile, Optional.set(bioOpt)("hello")); // new Profile with bio set
|
|
188
|
-
* pipe(profile, Optional.modify(bioOpt)(s => s + "!")); // appends if present
|
|
189
|
-
* ```
|
|
190
|
-
*/
|
|
191
|
-
type Optional<S, A> = {
|
|
192
|
-
readonly get: (s: S) => Maybe<A>;
|
|
193
|
-
readonly set: (a: A) => (s: S) => S;
|
|
194
|
-
};
|
|
195
|
-
declare namespace Optional {
|
|
196
|
-
/**
|
|
197
|
-
* Constructs an Optional from a getter (returning Maybe<A>) and a setter.
|
|
198
|
-
*
|
|
199
|
-
* @example
|
|
200
|
-
* ```ts
|
|
201
|
-
* const firstChar = Optional.make(
|
|
202
|
-
* (s: string) => s.length > 0 ? Maybe.some(s[0]) : Maybe.none(),
|
|
203
|
-
* (c) => (s) => s.length > 0 ? c + s.slice(1) : s,
|
|
204
|
-
* );
|
|
205
|
-
* ```
|
|
206
|
-
*/
|
|
207
|
-
const make: <S, A>(get: (s: S) => Maybe<A>, set: (a: A) => (s: S) => S) => Optional<S, A>;
|
|
208
|
-
/**
|
|
209
|
-
* Creates an Optional that focuses on an optional property of an object.
|
|
210
|
-
* Only keys whose type includes undefined (i.e. `field?: T`) are accepted.
|
|
211
|
-
* Call with the structure type first, then the key.
|
|
212
|
-
*
|
|
213
|
-
* @example
|
|
214
|
-
* ```ts
|
|
215
|
-
* type Profile = { username: string; bio?: string };
|
|
216
|
-
* const bioOpt = Optional.prop<Profile>()("bio");
|
|
217
|
-
* ```
|
|
218
|
-
*/
|
|
219
|
-
const prop: <S>() => <K extends OptionalKeys<S>>(key: K) => Optional<S, NonNullable<S[K]>>;
|
|
220
|
-
/**
|
|
221
|
-
* Creates an Optional that focuses on an element at a given index in an array.
|
|
222
|
-
* Returns None when the index is out of bounds; set is a no-op when out of bounds.
|
|
223
|
-
*
|
|
224
|
-
* @example
|
|
225
|
-
* ```ts
|
|
226
|
-
* const firstItem = Optional.index<string>(0);
|
|
227
|
-
*
|
|
228
|
-
* pipe(["a", "b"], Optional.get(firstItem)); // Some("a")
|
|
229
|
-
* pipe([], Optional.get(firstItem)); // None
|
|
230
|
-
* ```
|
|
231
|
-
*/
|
|
232
|
-
const index: <A>(i: number) => Optional<A[], A>;
|
|
233
|
-
/**
|
|
234
|
-
* Reads the focused value from a structure, returning Maybe<A>.
|
|
235
|
-
*
|
|
236
|
-
* @example
|
|
237
|
-
* ```ts
|
|
238
|
-
* pipe(profile, Optional.get(bioOpt)); // Some("...") or None
|
|
239
|
-
* ```
|
|
240
|
-
*/
|
|
241
|
-
const get: <S, A>(opt: Optional<S, A>) => (s: S) => Maybe<A>;
|
|
242
|
-
/**
|
|
243
|
-
* Replaces the focused value within a structure.
|
|
244
|
-
* For indexed focuses, this is a no-op when the index is out of bounds.
|
|
245
|
-
*
|
|
246
|
-
* @example
|
|
247
|
-
* ```ts
|
|
248
|
-
* pipe(profile, Optional.set(bioOpt)("hello"));
|
|
249
|
-
* ```
|
|
250
|
-
*/
|
|
251
|
-
const set: <S, A>(opt: Optional<S, A>) => (a: A) => (s: S) => S;
|
|
252
|
-
/**
|
|
253
|
-
* Applies a function to the focused value if it is present; returns the
|
|
254
|
-
* structure unchanged if the focus is absent.
|
|
255
|
-
*
|
|
256
|
-
* @example
|
|
257
|
-
* ```ts
|
|
258
|
-
* pipe(profile, Optional.modify(bioOpt)(s => s.toUpperCase()));
|
|
259
|
-
* ```
|
|
260
|
-
*/
|
|
261
|
-
const modify: <S, A>(opt: Optional<S, A>) => (f: (a: A) => A) => (s: S) => S;
|
|
262
|
-
/**
|
|
263
|
-
* Returns the focused value or a default when the focus is absent.
|
|
264
|
-
*
|
|
265
|
-
* @example
|
|
266
|
-
* ```ts
|
|
267
|
-
* pipe(profile, Optional.getOrElse(bioOpt)(() => "no bio"));
|
|
268
|
-
* ```
|
|
269
|
-
*/
|
|
270
|
-
const getOrElse: <S, A>(opt: Optional<S, A>) => (defaultValue: () => A) => (s: S) => A;
|
|
271
|
-
/**
|
|
272
|
-
* Extracts a value from an Optional focus using handlers for the present
|
|
273
|
-
* and absent cases.
|
|
274
|
-
*
|
|
275
|
-
* @example
|
|
276
|
-
* ```ts
|
|
277
|
-
* pipe(profile, Optional.fold(bioOpt)(() => "no bio", (bio) => bio.toUpperCase()));
|
|
278
|
-
* ```
|
|
279
|
-
*/
|
|
280
|
-
const fold: <S, A>(opt: Optional<S, A>) => <B>(onNone: () => B, onSome: (a: A) => B) => (s: S) => B;
|
|
281
|
-
/**
|
|
282
|
-
* Pattern matches on an Optional focus using a named-case object.
|
|
283
|
-
*
|
|
284
|
-
* @example
|
|
285
|
-
* ```ts
|
|
286
|
-
* pipe(
|
|
287
|
-
* profile,
|
|
288
|
-
* Optional.match(bioOpt)({ none: () => "no bio", some: (bio) => bio }),
|
|
289
|
-
* );
|
|
290
|
-
* ```
|
|
291
|
-
*/
|
|
292
|
-
const match: <S, A>(opt: Optional<S, A>) => <B>(cases: {
|
|
293
|
-
none: () => B;
|
|
294
|
-
some: (a: A) => B;
|
|
295
|
-
}) => (s: S) => B;
|
|
296
|
-
/**
|
|
297
|
-
* Composes two Optionals: focuses through the outer, then through the inner.
|
|
298
|
-
* Returns None if either focus is absent.
|
|
299
|
-
*
|
|
300
|
-
* @example
|
|
301
|
-
* ```ts
|
|
302
|
-
* const deepOpt = pipe(
|
|
303
|
-
* Optional.prop<User>()("address"),
|
|
304
|
-
* Optional.andThen(Optional.prop<Address>()("landmark")),
|
|
305
|
-
* );
|
|
306
|
-
* ```
|
|
307
|
-
*/
|
|
308
|
-
const andThen: <A, B>(inner: Optional<A, B>) => <S>(outer: Optional<S, A>) => Optional<S, B>;
|
|
309
|
-
/**
|
|
310
|
-
* Composes an Optional with a Lens, producing an Optional.
|
|
311
|
-
* The Lens focuses within the value found by the Optional.
|
|
312
|
-
*
|
|
313
|
-
* @example
|
|
314
|
-
* ```ts
|
|
315
|
-
* const cityOpt = pipe(
|
|
316
|
-
* Optional.prop<User>()("address"),
|
|
317
|
-
* Optional.andThenLens(Lens.prop<Address>()("city")),
|
|
318
|
-
* );
|
|
319
|
-
* ```
|
|
320
|
-
*/
|
|
321
|
-
const andThenLens: <A, B>(inner: Lens<A, B>) => <S>(outer: Optional<S, A>) => Optional<S, B>;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
169
|
/**
|
|
325
170
|
* Lens<S, A> focuses on a single value A inside a structure S, providing
|
|
326
171
|
* a composable way to read and immutably update nested data.
|
|
@@ -561,6 +406,27 @@ declare namespace Logged {
|
|
|
561
406
|
* ```
|
|
562
407
|
*/
|
|
563
408
|
const run: <W, A>(data: Logged<W, A>) => readonly [A, ReadonlyArray<W>];
|
|
409
|
+
/**
|
|
410
|
+
* Lifts a Logged value into an accumulator object.
|
|
411
|
+
*
|
|
412
|
+
* @example
|
|
413
|
+
* ```ts
|
|
414
|
+
* pipe(Logged.make<string, number>(42), Logged.bindTo("value")); // Logged({ value: 42 })
|
|
415
|
+
* ```
|
|
416
|
+
*/
|
|
417
|
+
const bindTo: <K extends string>(key: K) => <W, A>(data: Logged<W, A>) => Logged<W, { [P in K]: A; }>;
|
|
418
|
+
/**
|
|
419
|
+
* Evaluates a new Logged using the current accumulator and attaches the output to a new key.
|
|
420
|
+
*
|
|
421
|
+
* @example
|
|
422
|
+
* ```ts
|
|
423
|
+
* pipe(
|
|
424
|
+
* Logged.make<string, { a: number }>({ a: 1 }),
|
|
425
|
+
* Logged.bind("b", ({ a }) => Logged.make<string, number>(a + 1))
|
|
426
|
+
* ); // Logged({ value: { a: 1, b: 2 } })
|
|
427
|
+
* ```
|
|
428
|
+
*/
|
|
429
|
+
const bind: <K extends string, W, A, B>(key: K, f: (a: A) => Logged<W, B>) => (data: Logged<W, A>) => Logged<W, A & { [P in K]: B; }>;
|
|
564
430
|
}
|
|
565
431
|
|
|
566
432
|
type MaybeRetry<E, O> = O extends {
|
|
@@ -1265,140 +1131,159 @@ declare namespace Op {
|
|
|
1265
1131
|
function interpret<I, E, A, O extends AllInterpretOptions<I, E>>(op: Op<I, E, A>, options: O): InterpretResult<I, E, A, O>;
|
|
1266
1132
|
}
|
|
1267
1133
|
|
|
1134
|
+
/** Keys of T for which undefined is assignable (i.e. optional fields). */
|
|
1135
|
+
type OptionalKeys<T> = {
|
|
1136
|
+
[K in keyof T]-?: undefined extends T[K] ? K : never;
|
|
1137
|
+
}[keyof T];
|
|
1268
1138
|
/**
|
|
1269
|
-
* A
|
|
1139
|
+
* Optional<S, A> focuses on a value A inside a structure S that may or may
|
|
1140
|
+
* not be present. Like a Lens, but get returns Maybe<A>.
|
|
1270
1141
|
*
|
|
1271
|
-
*
|
|
1272
|
-
*
|
|
1273
|
-
* express domain invariants (non-empty strings, positive numbers, valid emails) as
|
|
1274
|
-
* first-class, composable values rather than one-off type guards scattered across
|
|
1275
|
-
* the codebase.
|
|
1142
|
+
* Compose with other Optionals via `andThen`, or with a Lens via `andThenLens`.
|
|
1143
|
+
* Convert a Lens to an Optional with `Lens.toOptional`.
|
|
1276
1144
|
*
|
|
1277
1145
|
* @example
|
|
1278
1146
|
* ```ts
|
|
1279
|
-
* type
|
|
1147
|
+
* type Profile = { username: string; bio?: string };
|
|
1280
1148
|
*
|
|
1281
|
-
* const
|
|
1282
|
-
* Refinement.make(s => s.length > 0);
|
|
1149
|
+
* const bioOpt = Optional.prop<Profile>()("bio");
|
|
1283
1150
|
*
|
|
1284
|
-
* pipe(
|
|
1285
|
-
*
|
|
1286
|
-
*
|
|
1287
|
-
* ); // Some("hello")
|
|
1151
|
+
* pipe(profile, Optional.get(bioOpt)); // Some("hello") or None
|
|
1152
|
+
* pipe(profile, Optional.set(bioOpt)("hello")); // new Profile with bio set
|
|
1153
|
+
* pipe(profile, Optional.modify(bioOpt)(s => s + "!")); // appends if present
|
|
1288
1154
|
* ```
|
|
1289
1155
|
*/
|
|
1290
|
-
type
|
|
1291
|
-
|
|
1156
|
+
type Optional<S, A> = {
|
|
1157
|
+
readonly get: (s: S) => Maybe<A>;
|
|
1158
|
+
readonly set: (a: A) => (s: S) => S;
|
|
1159
|
+
};
|
|
1160
|
+
declare namespace Optional {
|
|
1292
1161
|
/**
|
|
1293
|
-
*
|
|
1294
|
-
*
|
|
1295
|
-
* This is an unsafe cast — the caller is responsible for ensuring that the
|
|
1296
|
-
* predicate truly characterises values of type `B`. Use this only when
|
|
1297
|
-
* bootstrapping a new refinement; prefer `compose`, `and`, or `or` to build
|
|
1298
|
-
* derived refinements from existing ones.
|
|
1162
|
+
* Constructs an Optional from a getter (returning Maybe<A>) and a setter.
|
|
1299
1163
|
*
|
|
1300
1164
|
* @example
|
|
1301
1165
|
* ```ts
|
|
1302
|
-
*
|
|
1303
|
-
*
|
|
1304
|
-
*
|
|
1305
|
-
*
|
|
1166
|
+
* const firstChar = Optional.make(
|
|
1167
|
+
* (s: string) => s.length > 0 ? Maybe.some(s[0]) : Maybe.none(),
|
|
1168
|
+
* (c) => (s) => s.length > 0 ? c + s.slice(1) : s,
|
|
1169
|
+
* );
|
|
1306
1170
|
* ```
|
|
1307
1171
|
*/
|
|
1308
|
-
const make: <
|
|
1172
|
+
const make: <S, A>(get: (s: S) => Maybe<A>, set: (a: A) => (s: S) => S) => Optional<S, A>;
|
|
1309
1173
|
/**
|
|
1310
|
-
*
|
|
1311
|
-
*
|
|
1312
|
-
*
|
|
1313
|
-
* Data-last — the first refinement `ab` is the data being piped.
|
|
1174
|
+
* Creates an Optional that focuses on an optional property of an object.
|
|
1175
|
+
* Only keys whose type includes undefined (i.e. `field?: T`) are accepted.
|
|
1176
|
+
* Call with the structure type first, then the key.
|
|
1314
1177
|
*
|
|
1315
1178
|
* @example
|
|
1316
1179
|
* ```ts
|
|
1317
|
-
* type
|
|
1318
|
-
*
|
|
1319
|
-
*
|
|
1320
|
-
* const isNonEmpty: Refinement<string, NonEmptyString> =
|
|
1321
|
-
* Refinement.make(s => s.length > 0);
|
|
1322
|
-
* const isTrimmed: Refinement<NonEmptyString, TrimmedString> =
|
|
1323
|
-
* Refinement.make(s => s === s.trim());
|
|
1324
|
-
*
|
|
1325
|
-
* const isNonEmptyTrimmed: Refinement<string, TrimmedString> = pipe(
|
|
1326
|
-
* isNonEmpty,
|
|
1327
|
-
* Refinement.compose(isTrimmed)
|
|
1328
|
-
* );
|
|
1180
|
+
* type Profile = { username: string; bio?: string };
|
|
1181
|
+
* const bioOpt = Optional.prop<Profile>()("bio");
|
|
1329
1182
|
* ```
|
|
1330
1183
|
*/
|
|
1331
|
-
const
|
|
1184
|
+
const prop: <S>() => <K extends OptionalKeys<S>>(key: K) => Optional<S, NonNullable<S[K]>>;
|
|
1332
1185
|
/**
|
|
1333
|
-
*
|
|
1334
|
-
* when
|
|
1335
|
-
*
|
|
1336
|
-
* Data-last — the first refinement is the data being piped.
|
|
1186
|
+
* Creates an Optional that focuses on an element at a given index in an array.
|
|
1187
|
+
* Returns None when the index is out of bounds; set is a no-op when out of bounds.
|
|
1337
1188
|
*
|
|
1338
1189
|
* @example
|
|
1339
1190
|
* ```ts
|
|
1340
|
-
* const
|
|
1341
|
-
* const isNonEmpty: Refinement<unknown, { length: number }> =
|
|
1342
|
-
* Refinement.make(x => (x as any).length > 0);
|
|
1191
|
+
* const firstItem = Optional.index<string>(0);
|
|
1343
1192
|
*
|
|
1344
|
-
*
|
|
1345
|
-
*
|
|
1346
|
-
* isNonEmptyString(""); // false
|
|
1193
|
+
* pipe(["a", "b"], Optional.get(firstItem)); // Some("a")
|
|
1194
|
+
* pipe([], Optional.get(firstItem)); // None
|
|
1347
1195
|
* ```
|
|
1348
1196
|
*/
|
|
1349
|
-
const
|
|
1197
|
+
const index: <A>(i: number) => Optional<A[], A>;
|
|
1350
1198
|
/**
|
|
1351
|
-
*
|
|
1352
|
-
* refinement holds.
|
|
1353
|
-
*
|
|
1354
|
-
* Data-last — the first refinement is the data being piped.
|
|
1199
|
+
* Reads the focused value from a structure, returning Maybe<A>.
|
|
1355
1200
|
*
|
|
1356
1201
|
* @example
|
|
1357
1202
|
* ```ts
|
|
1358
|
-
*
|
|
1359
|
-
*
|
|
1203
|
+
* pipe(profile, Optional.get(bioOpt)); // Some("...") or None
|
|
1204
|
+
* ```
|
|
1205
|
+
*/
|
|
1206
|
+
const get: <S, A>(opt: Optional<S, A>) => (s: S) => Maybe<A>;
|
|
1207
|
+
/**
|
|
1208
|
+
* Replaces the focused value within a structure.
|
|
1209
|
+
* For indexed focuses, this is a no-op when the index is out of bounds.
|
|
1360
1210
|
*
|
|
1361
|
-
*
|
|
1362
|
-
*
|
|
1363
|
-
*
|
|
1364
|
-
* isStringOrNumber(true); // false
|
|
1211
|
+
* @example
|
|
1212
|
+
* ```ts
|
|
1213
|
+
* pipe(profile, Optional.set(bioOpt)("hello"));
|
|
1365
1214
|
* ```
|
|
1366
1215
|
*/
|
|
1367
|
-
const
|
|
1216
|
+
const set: <S, A>(opt: Optional<S, A>) => (a: A) => (s: S) => S;
|
|
1368
1217
|
/**
|
|
1369
|
-
*
|
|
1218
|
+
* Applies a function to the focused value if it is present; returns the
|
|
1219
|
+
* structure unchanged if the focus is absent.
|
|
1370
1220
|
*
|
|
1371
|
-
*
|
|
1372
|
-
*
|
|
1221
|
+
* @example
|
|
1222
|
+
* ```ts
|
|
1223
|
+
* pipe(profile, Optional.modify(bioOpt)(s => s.toUpperCase()));
|
|
1224
|
+
* ```
|
|
1225
|
+
*/
|
|
1226
|
+
const modify: <S, A>(opt: Optional<S, A>) => (f: (a: A) => A) => (s: S) => S;
|
|
1227
|
+
/**
|
|
1228
|
+
* Returns the focused value or a default when the focus is absent.
|
|
1373
1229
|
*
|
|
1374
1230
|
* @example
|
|
1375
1231
|
* ```ts
|
|
1376
|
-
*
|
|
1377
|
-
*
|
|
1378
|
-
|
|
1232
|
+
* pipe(profile, Optional.getOrElse(bioOpt)(() => "no bio"));
|
|
1233
|
+
* ```
|
|
1234
|
+
*/
|
|
1235
|
+
const getOrElse: <S, A>(opt: Optional<S, A>) => (defaultValue: () => A) => (s: S) => A;
|
|
1236
|
+
/**
|
|
1237
|
+
* Extracts a value from an Optional focus using handlers for the present
|
|
1238
|
+
* and absent cases.
|
|
1379
1239
|
*
|
|
1380
|
-
*
|
|
1381
|
-
*
|
|
1240
|
+
* @example
|
|
1241
|
+
* ```ts
|
|
1242
|
+
* pipe(profile, Optional.fold(bioOpt)(() => "no bio", (bio) => bio.toUpperCase()));
|
|
1382
1243
|
* ```
|
|
1383
1244
|
*/
|
|
1384
|
-
const
|
|
1245
|
+
const fold: <S, A>(opt: Optional<S, A>) => <B>(onNone: () => B, onSome: (a: A) => B) => (s: S) => B;
|
|
1385
1246
|
/**
|
|
1386
|
-
*
|
|
1247
|
+
* Pattern matches on an Optional focus using a named-case object.
|
|
1387
1248
|
*
|
|
1388
|
-
*
|
|
1389
|
-
*
|
|
1249
|
+
* @example
|
|
1250
|
+
* ```ts
|
|
1251
|
+
* pipe(
|
|
1252
|
+
* profile,
|
|
1253
|
+
* Optional.match(bioOpt)({ none: () => "no bio", some: (bio) => bio }),
|
|
1254
|
+
* );
|
|
1255
|
+
* ```
|
|
1256
|
+
*/
|
|
1257
|
+
const match: <S, A>(opt: Optional<S, A>) => <B>(cases: {
|
|
1258
|
+
none: () => B;
|
|
1259
|
+
some: (a: A) => B;
|
|
1260
|
+
}) => (s: S) => B;
|
|
1261
|
+
/**
|
|
1262
|
+
* Composes two Optionals: focuses through the outer, then through the inner.
|
|
1263
|
+
* Returns None if either focus is absent.
|
|
1390
1264
|
*
|
|
1391
1265
|
* @example
|
|
1392
1266
|
* ```ts
|
|
1393
|
-
*
|
|
1394
|
-
*
|
|
1395
|
-
*
|
|
1267
|
+
* const deepOpt = pipe(
|
|
1268
|
+
* Optional.prop<User>()("address"),
|
|
1269
|
+
* Optional.andThen(Optional.prop<Address>()("landmark")),
|
|
1270
|
+
* );
|
|
1271
|
+
* ```
|
|
1272
|
+
*/
|
|
1273
|
+
const andThen: <A, B>(inner: Optional<A, B>) => <S>(outer: Optional<S, A>) => Optional<S, B>;
|
|
1274
|
+
/**
|
|
1275
|
+
* Composes an Optional with a Lens, producing an Optional.
|
|
1276
|
+
* The Lens focuses within the value found by the Optional.
|
|
1396
1277
|
*
|
|
1397
|
-
*
|
|
1398
|
-
*
|
|
1278
|
+
* @example
|
|
1279
|
+
* ```ts
|
|
1280
|
+
* const cityOpt = pipe(
|
|
1281
|
+
* Optional.prop<User>()("address"),
|
|
1282
|
+
* Optional.andThenLens(Lens.prop<Address>()("city")),
|
|
1283
|
+
* );
|
|
1399
1284
|
* ```
|
|
1400
1285
|
*/
|
|
1401
|
-
const
|
|
1286
|
+
const andThenLens: <A, B>(inner: Lens<A, B>) => <S>(outer: Optional<S, A>) => Optional<S, B>;
|
|
1402
1287
|
}
|
|
1403
1288
|
|
|
1404
1289
|
/**
|
|
@@ -1715,6 +1600,163 @@ declare namespace Reader {
|
|
|
1715
1600
|
* ```
|
|
1716
1601
|
*/
|
|
1717
1602
|
const run: <R>(env: R) => <A>(data: Reader<R, A>) => A;
|
|
1603
|
+
/**
|
|
1604
|
+
* Lifts a Reader value into an accumulator object.
|
|
1605
|
+
*
|
|
1606
|
+
* @example
|
|
1607
|
+
* ```ts
|
|
1608
|
+
* pipe(Reader.resolve(42), Reader.bindTo("value")); // Reader({ value: 42 })
|
|
1609
|
+
* ```
|
|
1610
|
+
*/
|
|
1611
|
+
const bindTo: <K extends string>(key: K) => <R, A>(data: Reader<R, A>) => Reader<R, { [P in K]: A; }>;
|
|
1612
|
+
/**
|
|
1613
|
+
* Evaluates a new Reader using the current accumulator and attaches the output to a new key.
|
|
1614
|
+
*
|
|
1615
|
+
* @example
|
|
1616
|
+
* ```ts
|
|
1617
|
+
* pipe(
|
|
1618
|
+
* Reader.resolve({ a: 1 }),
|
|
1619
|
+
* Reader.bind("b", ({ a }) => Reader.resolve(a + 1))
|
|
1620
|
+
* ); // Reader({ a: 1, b: 2 })
|
|
1621
|
+
* ```
|
|
1622
|
+
*/
|
|
1623
|
+
const bind: <K extends string, R, A, B>(key: K, f: (a: A) => Reader<R, B>) => (data: Reader<R, A>) => Reader<R, A & { [P in K]: B; }>;
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1626
|
+
/**
|
|
1627
|
+
* A function from `A` to `A is B` — a type predicate paired with a runtime check.
|
|
1628
|
+
*
|
|
1629
|
+
* A `Refinement<A, B>` proves at compile time that a value of type `A` is actually
|
|
1630
|
+
* the narrower type `B extends A`, backed by a runtime boolean test. Use it to
|
|
1631
|
+
* express domain invariants (non-empty strings, positive numbers, valid emails) as
|
|
1632
|
+
* first-class, composable values rather than one-off type guards scattered across
|
|
1633
|
+
* the codebase.
|
|
1634
|
+
*
|
|
1635
|
+
* @example
|
|
1636
|
+
* ```ts
|
|
1637
|
+
* type NonEmptyString = string & { readonly _tag: "NonEmptyString" };
|
|
1638
|
+
*
|
|
1639
|
+
* const isNonEmpty: Refinement<string, NonEmptyString> =
|
|
1640
|
+
* Refinement.make(s => s.length > 0);
|
|
1641
|
+
*
|
|
1642
|
+
* pipe(
|
|
1643
|
+
* "hello",
|
|
1644
|
+
* Refinement.toFilter(isNonEmpty)
|
|
1645
|
+
* ); // Some("hello")
|
|
1646
|
+
* ```
|
|
1647
|
+
*/
|
|
1648
|
+
type Refinement<A, B extends A> = (a: A) => a is B;
|
|
1649
|
+
declare namespace Refinement {
|
|
1650
|
+
/**
|
|
1651
|
+
* Creates a `Refinement<A, B>` from a plain boolean predicate.
|
|
1652
|
+
*
|
|
1653
|
+
* This is an unsafe cast — the caller is responsible for ensuring that the
|
|
1654
|
+
* predicate truly characterises values of type `B`. Use this only when
|
|
1655
|
+
* bootstrapping a new refinement; prefer `compose`, `and`, or `or` to build
|
|
1656
|
+
* derived refinements from existing ones.
|
|
1657
|
+
*
|
|
1658
|
+
* @example
|
|
1659
|
+
* ```ts
|
|
1660
|
+
* type PositiveNumber = number & { readonly _tag: "PositiveNumber" };
|
|
1661
|
+
*
|
|
1662
|
+
* const isPositive: Refinement<number, PositiveNumber> =
|
|
1663
|
+
* Refinement.make(n => n > 0);
|
|
1664
|
+
* ```
|
|
1665
|
+
*/
|
|
1666
|
+
const make: <A, B extends A>(f: (a: A) => boolean) => Refinement<A, B>;
|
|
1667
|
+
/**
|
|
1668
|
+
* Chains two refinements: if `ab` narrows `A` to `B` and `bc` narrows `B` to `C`,
|
|
1669
|
+
* the result narrows `A` directly to `C`.
|
|
1670
|
+
*
|
|
1671
|
+
* Data-last — the first refinement `ab` is the data being piped.
|
|
1672
|
+
*
|
|
1673
|
+
* @example
|
|
1674
|
+
* ```ts
|
|
1675
|
+
* type NonEmptyString = string & { readonly _tag: "NonEmpty" };
|
|
1676
|
+
* type TrimmedString = NonEmptyString & { readonly _tag: "Trimmed" };
|
|
1677
|
+
*
|
|
1678
|
+
* const isNonEmpty: Refinement<string, NonEmptyString> =
|
|
1679
|
+
* Refinement.make(s => s.length > 0);
|
|
1680
|
+
* const isTrimmed: Refinement<NonEmptyString, TrimmedString> =
|
|
1681
|
+
* Refinement.make(s => s === s.trim());
|
|
1682
|
+
*
|
|
1683
|
+
* const isNonEmptyTrimmed: Refinement<string, TrimmedString> = pipe(
|
|
1684
|
+
* isNonEmpty,
|
|
1685
|
+
* Refinement.compose(isTrimmed)
|
|
1686
|
+
* );
|
|
1687
|
+
* ```
|
|
1688
|
+
*/
|
|
1689
|
+
const compose: <A, B extends A, C extends B>(bc: Refinement<B, C>) => (ab: Refinement<A, B>) => Refinement<A, C>;
|
|
1690
|
+
/**
|
|
1691
|
+
* Intersects two refinements: the result narrows `A` to `B & C`, passing only
|
|
1692
|
+
* when both refinements hold simultaneously.
|
|
1693
|
+
*
|
|
1694
|
+
* Data-last — the first refinement is the data being piped.
|
|
1695
|
+
*
|
|
1696
|
+
* @example
|
|
1697
|
+
* ```ts
|
|
1698
|
+
* const isString: Refinement<unknown, string> = Refinement.make(x => typeof x === "string");
|
|
1699
|
+
* const isNonEmpty: Refinement<unknown, { length: number }> =
|
|
1700
|
+
* Refinement.make(x => (x as any).length > 0);
|
|
1701
|
+
*
|
|
1702
|
+
* const isNonEmptyString = pipe(isString, Refinement.and(isNonEmpty));
|
|
1703
|
+
* isNonEmptyString("hi"); // true
|
|
1704
|
+
* isNonEmptyString(""); // false
|
|
1705
|
+
* ```
|
|
1706
|
+
*/
|
|
1707
|
+
const and: <A, C extends A>(second: Refinement<A, C>) => <B extends A>(first: Refinement<A, B>) => Refinement<A, B & C>;
|
|
1708
|
+
/**
|
|
1709
|
+
* Unions two refinements: the result narrows `A` to `B | C`, passing when either
|
|
1710
|
+
* refinement holds.
|
|
1711
|
+
*
|
|
1712
|
+
* Data-last — the first refinement is the data being piped.
|
|
1713
|
+
*
|
|
1714
|
+
* @example
|
|
1715
|
+
* ```ts
|
|
1716
|
+
* const isString: Refinement<unknown, string> = Refinement.make(x => typeof x === "string");
|
|
1717
|
+
* const isNumber: Refinement<unknown, number> = Refinement.make(x => typeof x === "number");
|
|
1718
|
+
*
|
|
1719
|
+
* const isStringOrNumber = pipe(isString, Refinement.or(isNumber));
|
|
1720
|
+
* isStringOrNumber("hi"); // true
|
|
1721
|
+
* isStringOrNumber(42); // true
|
|
1722
|
+
* isStringOrNumber(true); // false
|
|
1723
|
+
* ```
|
|
1724
|
+
*/
|
|
1725
|
+
const or: <A, C extends A>(second: Refinement<A, C>) => <B extends A>(first: Refinement<A, B>) => Refinement<A, B | C>;
|
|
1726
|
+
/**
|
|
1727
|
+
* Converts a `Refinement<A, B>` into a function `(a: A) => Maybe<B>`.
|
|
1728
|
+
*
|
|
1729
|
+
* Returns `Some(a)` when the refinement holds, `None` otherwise. Useful for
|
|
1730
|
+
* integrating runtime validation into a `Maybe`-based pipeline.
|
|
1731
|
+
*
|
|
1732
|
+
* @example
|
|
1733
|
+
* ```ts
|
|
1734
|
+
* type PositiveNumber = number & { readonly _tag: "Positive" };
|
|
1735
|
+
* const isPositive: Refinement<number, PositiveNumber> =
|
|
1736
|
+
* Refinement.make(n => n > 0);
|
|
1737
|
+
*
|
|
1738
|
+
* pipe(-1, Refinement.toFilter(isPositive)); // None
|
|
1739
|
+
* pipe(42, Refinement.toFilter(isPositive)); // Some(42)
|
|
1740
|
+
* ```
|
|
1741
|
+
*/
|
|
1742
|
+
const toFilter: <A, B extends A>(r: Refinement<A, B>) => (a: A) => Maybe<B>;
|
|
1743
|
+
/**
|
|
1744
|
+
* Converts a `Refinement<A, B>` into a function `(a: A) => Result<E, B>`.
|
|
1745
|
+
*
|
|
1746
|
+
* Returns `Ok(a)` when the refinement holds, `Err(onFail(a))` otherwise. Use
|
|
1747
|
+
* this to surface validation failures as typed errors inside a `Result` pipeline.
|
|
1748
|
+
*
|
|
1749
|
+
* @example
|
|
1750
|
+
* ```ts
|
|
1751
|
+
* type NonEmptyString = string & { readonly _tag: "NonEmpty" };
|
|
1752
|
+
* const isNonEmpty: Refinement<string, NonEmptyString> =
|
|
1753
|
+
* Refinement.make(s => s.length > 0);
|
|
1754
|
+
*
|
|
1755
|
+
* pipe("", Refinement.toResult(isNonEmpty, () => "must not be empty")); // Err(...)
|
|
1756
|
+
* pipe("hi", Refinement.toResult(isNonEmpty, () => "must not be empty")); // Ok("hi")
|
|
1757
|
+
* ```
|
|
1758
|
+
*/
|
|
1759
|
+
const toResult: <A, B extends A, E>(r: Refinement<A, B>, onFail: (a: A) => E) => (a: A) => Result<E, B>;
|
|
1718
1760
|
}
|
|
1719
1761
|
|
|
1720
1762
|
type NotAsked = WithKind<"NotAsked">;
|
|
@@ -1962,140 +2004,7 @@ declare namespace RemoteData {
|
|
|
1962
2004
|
}
|
|
1963
2005
|
|
|
1964
2006
|
/**
|
|
1965
|
-
* A
|
|
1966
|
-
* Combines async operations with typed error handling.
|
|
1967
|
-
*
|
|
1968
|
-
* @example
|
|
1969
|
-
* ```ts
|
|
1970
|
-
* const fetchUser = (id: string): TaskResult<Error, User> =>
|
|
1971
|
-
* TaskResult.tryCatch(
|
|
1972
|
-
* (signal) => fetch(`/users/${id}`, { signal }).then(r => r.json()),
|
|
1973
|
-
* (e) => new Error(`Failed to fetch user: ${e}`)
|
|
1974
|
-
* );
|
|
1975
|
-
* ```
|
|
1976
|
-
*/
|
|
1977
|
-
type TaskResult<E, A> = Task<Result<E, A>>;
|
|
1978
|
-
declare namespace TaskResult {
|
|
1979
|
-
/**
|
|
1980
|
-
* Wraps a value in a successful TaskResult.
|
|
1981
|
-
*/
|
|
1982
|
-
const ok: <E, A>(value: A) => TaskResult<E, A>;
|
|
1983
|
-
/**
|
|
1984
|
-
* Creates a failed TaskResult with the given error.
|
|
1985
|
-
*/
|
|
1986
|
-
const err: <E, A>(error: E) => TaskResult<E, A>;
|
|
1987
|
-
/**
|
|
1988
|
-
* Creates a TaskResult from a nullable value.
|
|
1989
|
-
* Returns Ok if the value is not null or undefined, err from onNull otherwise.
|
|
1990
|
-
*/
|
|
1991
|
-
const fromNullable: <E>(onNull: () => E) => <A>(value: A | null | undefined) => TaskResult<E, A>;
|
|
1992
|
-
/**
|
|
1993
|
-
* Creates a TaskResult from a Maybe.
|
|
1994
|
-
* Some becomes Ok, None becomes err from onNone.
|
|
1995
|
-
*/
|
|
1996
|
-
const fromMaybe: <E>(onNone: () => E) => <A>(maybe: Maybe<A>) => TaskResult<E, A>;
|
|
1997
|
-
/**
|
|
1998
|
-
* Lifts a Result into a TaskResult.
|
|
1999
|
-
*/
|
|
2000
|
-
const fromResult: <E, A>(result: Result<E, A>) => TaskResult<E, A>;
|
|
2001
|
-
/**
|
|
2002
|
-
* Wraps a Promise-returning function of any arguments, returning a new function
|
|
2003
|
-
* that catches rejections and returns a TaskResult.
|
|
2004
|
-
*/
|
|
2005
|
-
const fromThrowable: <Args extends readonly unknown[], A, E>(f: (...args: Args) => Promise<A>, onError: (e: unknown) => E) => (...args: Args) => TaskResult<E, A>;
|
|
2006
|
-
/**
|
|
2007
|
-
* Creates a TaskResult from a function that may throw.
|
|
2008
|
-
* Catches any errors and transforms them using the onError function.
|
|
2009
|
-
* The factory optionally receives an `AbortSignal` forwarded from the call site.
|
|
2010
|
-
*
|
|
2011
|
-
* @example
|
|
2012
|
-
* ```ts
|
|
2013
|
-
* const fetchUser = (id: string): TaskResult<string, User> =>
|
|
2014
|
-
* TaskResult.tryCatch(
|
|
2015
|
-
* (signal) => fetch(`/users/${id}`, { signal }).then(r => r.json()),
|
|
2016
|
-
* String
|
|
2017
|
-
* );
|
|
2018
|
-
* ```
|
|
2019
|
-
*/
|
|
2020
|
-
const tryCatch: <E, A>(f: (signal?: AbortSignal) => Promise<A>, onError: (e: unknown) => E) => TaskResult<E, A>;
|
|
2021
|
-
/**
|
|
2022
|
-
* Transforms the success value inside a TaskResult.
|
|
2023
|
-
*/
|
|
2024
|
-
const map: <E, A, B>(f: (a: A) => B) => (data: TaskResult<E, A>) => TaskResult<E, B>;
|
|
2025
|
-
/**
|
|
2026
|
-
* Transforms the error value inside a TaskResult.
|
|
2027
|
-
*/
|
|
2028
|
-
const mapError: <E, F, A>(f: (e: E) => F) => (data: TaskResult<E, A>) => TaskResult<F, A>;
|
|
2029
|
-
/**
|
|
2030
|
-
* Chains TaskResult computations. If the first succeeds, passes the value to f.
|
|
2031
|
-
* If the first fails, propagates the error.
|
|
2032
|
-
*/
|
|
2033
|
-
const chain: <E, A, B>(f: (a: A) => TaskResult<E, B>) => (data: TaskResult<E, A>) => TaskResult<E, B>;
|
|
2034
|
-
/**
|
|
2035
|
-
* Extracts the value from a TaskResult by providing handlers for both cases.
|
|
2036
|
-
*/
|
|
2037
|
-
const fold: <E, A, B>(onErr: (e: E) => B, onOk: (a: A) => B) => (data: TaskResult<E, A>) => Task<B>;
|
|
2038
|
-
/**
|
|
2039
|
-
* Pattern matches on a TaskResult, returning a Task of the result.
|
|
2040
|
-
*/
|
|
2041
|
-
const match: <E, A, B>(cases: {
|
|
2042
|
-
err: (e: E) => B;
|
|
2043
|
-
ok: (a: A) => B;
|
|
2044
|
-
}) => (data: TaskResult<E, A>) => Task<B>;
|
|
2045
|
-
/**
|
|
2046
|
-
* Recovers from an error by providing a fallback TaskResult.
|
|
2047
|
-
* The fallback can produce a different success type, widening the result to `TaskResult<E, A | B>`.
|
|
2048
|
-
*/
|
|
2049
|
-
const recover: <E, A, B>(fallback: (e: E) => TaskResult<E, B>) => (data: TaskResult<E, A>) => TaskResult<E, A | B>;
|
|
2050
|
-
/**
|
|
2051
|
-
* Returns the success value or a default value if the TaskResult is an error.
|
|
2052
|
-
* The default can be a different type, widening the result to `Task<A | B>`.
|
|
2053
|
-
*/
|
|
2054
|
-
const getOrElse: <E, A, B>(defaultValue: () => B) => (data: TaskResult<E, A>) => Task<A | B>;
|
|
2055
|
-
/**
|
|
2056
|
-
* Executes a side effect on the success value without changing the TaskResult.
|
|
2057
|
-
* Useful for logging or debugging.
|
|
2058
|
-
*/
|
|
2059
|
-
const tap: <E, A>(f: (a: A) => void) => (data: TaskResult<E, A>) => TaskResult<E, A>;
|
|
2060
|
-
/**
|
|
2061
|
-
* Executes a side effect on the error value without changing the TaskResult.
|
|
2062
|
-
* Useful for logging or reporting async errors.
|
|
2063
|
-
*
|
|
2064
|
-
* @example
|
|
2065
|
-
* ```ts
|
|
2066
|
-
* pipe(
|
|
2067
|
-
* fetchUser(id),
|
|
2068
|
-
* TaskResult.tapError(e => console.error("fetch failed:", e)),
|
|
2069
|
-
* TaskResult.chain(saveToCache),
|
|
2070
|
-
* )
|
|
2071
|
-
* ```
|
|
2072
|
-
*/
|
|
2073
|
-
const tapError: <E, A>(f: (e: E) => void) => (data: TaskResult<E, A>) => TaskResult<E, A>;
|
|
2074
|
-
/**
|
|
2075
|
-
* Applies a function wrapped in a TaskResult to a value wrapped in a TaskResult.
|
|
2076
|
-
* Both Tasks run in parallel.
|
|
2077
|
-
*/
|
|
2078
|
-
const ap: <E, A>(arg: TaskResult<E, A>) => <B>(data: TaskResult<E, (a: A) => B>) => TaskResult<E, B>;
|
|
2079
|
-
/**
|
|
2080
|
-
* Executes a `TaskResult` with an optional signal, returning `Promise<Result<E, A>>`.
|
|
2081
|
-
* Use as a terminal step in a `pipe` chain.
|
|
2082
|
-
*
|
|
2083
|
-
* @example
|
|
2084
|
-
* ```ts
|
|
2085
|
-
* const controller = new AbortController();
|
|
2086
|
-
* const result = await pipe(
|
|
2087
|
-
* fetchUser("42"),
|
|
2088
|
-
* TaskResult.chain(user => fetchPosts(user.id)),
|
|
2089
|
-
* TaskResult.run(controller.signal),
|
|
2090
|
-
* );
|
|
2091
|
-
* if (Result.isOk(result)) render(result.value);
|
|
2092
|
-
* ```
|
|
2093
|
-
*/
|
|
2094
|
-
const run: (signal?: AbortSignal) => <E, A>(task: TaskResult<E, A>) => Promise<Result<E, A>>;
|
|
2095
|
-
}
|
|
2096
|
-
|
|
2097
|
-
/**
|
|
2098
|
-
* A Resource pairs an async acquisition step with a guaranteed cleanup step.
|
|
2007
|
+
* A Resource pairs an async acquisition step with a guaranteed cleanup step.
|
|
2099
2008
|
*
|
|
2100
2009
|
* Use it whenever something must be explicitly closed, released, or torn down
|
|
2101
2010
|
* after you are done with it — database connections, file handles, locks,
|
|
@@ -2379,6 +2288,27 @@ declare namespace State {
|
|
|
2379
2288
|
* ```
|
|
2380
2289
|
*/
|
|
2381
2290
|
const execute: <S>(initialState: S) => <A>(st: State<S, A>) => S;
|
|
2291
|
+
/**
|
|
2292
|
+
* Lifts a State value into an accumulator object.
|
|
2293
|
+
*
|
|
2294
|
+
* @example
|
|
2295
|
+
* ```ts
|
|
2296
|
+
* pipe(State.resolve(42), State.bindTo("value")); // State({ value: 42 })
|
|
2297
|
+
* ```
|
|
2298
|
+
*/
|
|
2299
|
+
const bindTo: <K extends string>(key: K) => <S, A>(data: State<S, A>) => State<S, { [P in K]: A; }>;
|
|
2300
|
+
/**
|
|
2301
|
+
* Evaluates a new State using the current accumulator and attaches the output to a new key.
|
|
2302
|
+
*
|
|
2303
|
+
* @example
|
|
2304
|
+
* ```ts
|
|
2305
|
+
* pipe(
|
|
2306
|
+
* State.resolve({ a: 1 }),
|
|
2307
|
+
* State.bind("b", ({ a }) => State.resolve(a + 1))
|
|
2308
|
+
* ); // State({ a: 1, b: 2 })
|
|
2309
|
+
* ```
|
|
2310
|
+
*/
|
|
2311
|
+
const bind: <K extends string, S, A, B>(key: K, f: (a: A) => State<S, B>) => (data: State<S, A>) => State<S, A & { [P in K]: B; }>;
|
|
2382
2312
|
}
|
|
2383
2313
|
|
|
2384
2314
|
/**
|
|
@@ -2508,313 +2438,196 @@ declare namespace TaskMaybe {
|
|
|
2508
2438
|
* ```
|
|
2509
2439
|
*/
|
|
2510
2440
|
const toTaskResult: <E>(onNone: () => E) => <A>(data: TaskMaybe<A>) => TaskResult<E, A>;
|
|
2511
|
-
}
|
|
2512
|
-
|
|
2513
|
-
type Passed<A> = WithKind<"Passed"> & WithValue<A>;
|
|
2514
|
-
type Failed<E> = WithKind<"Failed"> & WithErrors<E>;
|
|
2515
|
-
/**
|
|
2516
|
-
* Validation represents a value that is either passed with a success value,
|
|
2517
|
-
* or failed with accumulated errors.
|
|
2518
|
-
* Unlike Result, Validation can accumulate multiple errors instead of short-circuiting.
|
|
2519
|
-
*
|
|
2520
|
-
* Use Validation when you need to collect all errors (e.g., form validation).
|
|
2521
|
-
* Use Result when you want to fail fast on the first error.
|
|
2522
|
-
*
|
|
2523
|
-
* @example
|
|
2524
|
-
* ```ts
|
|
2525
|
-
* const validateName = (name: string): Validation<string, string> =>
|
|
2526
|
-
* name.length > 0 ? Validation.passed(name) : Validation.failed("Name is required");
|
|
2527
|
-
*
|
|
2528
|
-
* const validateAge = (age: number): Validation<string, number> =>
|
|
2529
|
-
* age >= 0 ? Validation.passed(age) : Validation.failed("Age must be positive");
|
|
2530
|
-
*
|
|
2531
|
-
* // Accumulates all errors using ap
|
|
2532
|
-
* pipe(
|
|
2533
|
-
* Validation.passed((name: string) => (age: number) => ({ name, age })),
|
|
2534
|
-
* Validation.ap(validateName("")),
|
|
2535
|
-
* Validation.ap(validateAge(-1))
|
|
2536
|
-
* );
|
|
2537
|
-
* // Failed(["Name is required", "Age must be positive"])
|
|
2538
|
-
* ```
|
|
2539
|
-
*/
|
|
2540
|
-
type Validation<E, A> = Passed<A> | Failed<E>;
|
|
2541
|
-
declare namespace Validation {
|
|
2542
2441
|
/**
|
|
2543
|
-
*
|
|
2442
|
+
* Lifts a TaskMaybe value into an accumulator object.
|
|
2544
2443
|
*
|
|
2545
2444
|
* @example
|
|
2546
2445
|
* ```ts
|
|
2547
|
-
*
|
|
2446
|
+
* pipe(TaskMaybe.some(42), TaskMaybe.bindTo("value")); // TaskMaybe({ value: 42 })
|
|
2548
2447
|
* ```
|
|
2549
2448
|
*/
|
|
2550
|
-
const
|
|
2449
|
+
const bindTo: <K extends string>(key: K) => <A>(data: TaskMaybe<A>) => TaskMaybe<{ [P in K]: A; }>;
|
|
2551
2450
|
/**
|
|
2552
|
-
*
|
|
2451
|
+
* Evaluates a new TaskMaybe using the current accumulator and attaches the output to a new key.
|
|
2553
2452
|
*
|
|
2554
2453
|
* @example
|
|
2555
2454
|
* ```ts
|
|
2556
|
-
*
|
|
2455
|
+
* pipe(
|
|
2456
|
+
* TaskMaybe.some({ a: 1 }),
|
|
2457
|
+
* TaskMaybe.bind("b", ({ a }) => TaskMaybe.some(a + 1))
|
|
2458
|
+
* ); // TaskMaybe({ a: 1, b: 2 })
|
|
2557
2459
|
* ```
|
|
2558
2460
|
*/
|
|
2559
|
-
const
|
|
2461
|
+
const bind: <K extends string, A, B>(key: K, f: (a: A) => TaskMaybe<B>) => (data: TaskMaybe<A>) => TaskMaybe<A & { [P in K]: B; }>;
|
|
2462
|
+
}
|
|
2463
|
+
|
|
2464
|
+
/**
|
|
2465
|
+
* A Task that can fail with an error of type E or succeed with a value of type A.
|
|
2466
|
+
* Combines async operations with typed error handling.
|
|
2467
|
+
*
|
|
2468
|
+
* @example
|
|
2469
|
+
* ```ts
|
|
2470
|
+
* const fetchUser = (id: string): TaskResult<Error, User> =>
|
|
2471
|
+
* TaskResult.tryCatch(
|
|
2472
|
+
* (signal) => fetch(`/users/${id}`, { signal }).then(r => r.json()),
|
|
2473
|
+
* (e) => new Error(`Failed to fetch user: ${e}`)
|
|
2474
|
+
* );
|
|
2475
|
+
* ```
|
|
2476
|
+
*/
|
|
2477
|
+
type TaskResult<E, A> = Task<Result<E, A>>;
|
|
2478
|
+
declare namespace TaskResult {
|
|
2560
2479
|
/**
|
|
2561
|
-
*
|
|
2562
|
-
*
|
|
2563
|
-
* @example
|
|
2564
|
-
* ```ts
|
|
2565
|
-
* Validation.failedAll(["Invalid input"]);
|
|
2566
|
-
* ```
|
|
2480
|
+
* Wraps a value in a successful TaskResult.
|
|
2567
2481
|
*/
|
|
2568
|
-
const
|
|
2482
|
+
const ok: <E, A>(value: A) => TaskResult<E, A>;
|
|
2569
2483
|
/**
|
|
2570
|
-
*
|
|
2484
|
+
* Creates a failed TaskResult with the given error.
|
|
2571
2485
|
*/
|
|
2572
|
-
const
|
|
2486
|
+
const err: <E, A>(error: E) => TaskResult<E, A>;
|
|
2573
2487
|
/**
|
|
2574
|
-
*
|
|
2488
|
+
* Creates a TaskResult from a nullable value.
|
|
2489
|
+
* Returns Ok if the value is not null or undefined, err from onNull otherwise.
|
|
2575
2490
|
*/
|
|
2576
|
-
const
|
|
2491
|
+
const fromNullable: <E>(onNull: () => E) => <A>(value: A | null | undefined) => TaskResult<E, A>;
|
|
2577
2492
|
/**
|
|
2578
|
-
* Creates a
|
|
2579
|
-
*
|
|
2580
|
-
*
|
|
2581
|
-
* @example
|
|
2582
|
-
* ```ts
|
|
2583
|
-
* const validateName = Validation.fromPredicate(
|
|
2584
|
-
* (s: string) => s.length > 0,
|
|
2585
|
-
* () => "Name is required"
|
|
2586
|
-
* );
|
|
2587
|
-
*
|
|
2588
|
-
* validateName("Alice"); // Passed("Alice")
|
|
2589
|
-
* validateName(""); // Failed(["Name is required"])
|
|
2590
|
-
* ```
|
|
2493
|
+
* Creates a TaskResult from a Maybe.
|
|
2494
|
+
* Some becomes Ok, None becomes err from onNone.
|
|
2591
2495
|
*/
|
|
2592
|
-
const
|
|
2496
|
+
const fromMaybe: <E>(onNone: () => E) => <A>(maybe: Maybe<A>) => TaskResult<E, A>;
|
|
2593
2497
|
/**
|
|
2594
|
-
*
|
|
2595
|
-
|
|
2596
|
-
|
|
2498
|
+
* Lifts a Result into a TaskResult.
|
|
2499
|
+
*/
|
|
2500
|
+
const fromResult: <E, A>(result: Result<E, A>) => TaskResult<E, A>;
|
|
2501
|
+
/**
|
|
2502
|
+
* Wraps a Promise-returning function of any arguments, returning a new function
|
|
2503
|
+
* that catches rejections and returns a TaskResult.
|
|
2504
|
+
*/
|
|
2505
|
+
const fromThrowable: <Args extends readonly unknown[], A, E>(f: (...args: Args) => Promise<A>, onError: (e: unknown) => E) => (...args: Args) => TaskResult<E, A>;
|
|
2506
|
+
/**
|
|
2507
|
+
* Creates a TaskResult from a function that may throw.
|
|
2508
|
+
* Catches any errors and transforms them using the onError function.
|
|
2509
|
+
* The factory optionally receives an `AbortSignal` forwarded from the call site.
|
|
2597
2510
|
*
|
|
2598
2511
|
* @example
|
|
2599
2512
|
* ```ts
|
|
2600
|
-
*
|
|
2601
|
-
*
|
|
2513
|
+
* const fetchUser = (id: string): TaskResult<string, User> =>
|
|
2514
|
+
* TaskResult.tryCatch(
|
|
2515
|
+
* (signal) => fetch(`/users/${id}`, { signal }).then(r => r.json()),
|
|
2516
|
+
* String
|
|
2517
|
+
* );
|
|
2602
2518
|
* ```
|
|
2603
2519
|
*/
|
|
2604
|
-
const
|
|
2520
|
+
const tryCatch: <E, A>(f: (signal?: AbortSignal) => Promise<A>, onError: (e: unknown) => E) => TaskResult<E, A>;
|
|
2605
2521
|
/**
|
|
2606
|
-
*
|
|
2607
|
-
* If the Maybe is None, returns Failed with the error from onNone.
|
|
2608
|
-
* Otherwise, returns Passed.
|
|
2609
|
-
*
|
|
2610
|
-
* @example
|
|
2611
|
-
* ```ts
|
|
2612
|
-
* pipe(Maybe.none(), Validation.fromMaybe(() => "is none")); // Failed(["is none"])
|
|
2613
|
-
* pipe(Maybe.some(42), Validation.fromMaybe(() => "is none")); // Passed(42)
|
|
2614
|
-
* ```
|
|
2615
|
-
*/
|
|
2616
|
-
const fromMaybe: <E>(onNone: () => E) => <A>(maybe: Maybe<A>) => Validation<E, A>;
|
|
2617
|
-
/**
|
|
2618
|
-
* Transforms the success value inside a Validation.
|
|
2619
|
-
*
|
|
2620
|
-
* @example
|
|
2621
|
-
* ```ts
|
|
2622
|
-
* pipe(Validation.passed(5), Validation.map(n => n * 2)); // Passed(10)
|
|
2623
|
-
* pipe(Validation.failed("oops"), Validation.map(n => n * 2)); // Failed(["oops"])
|
|
2624
|
-
* ```
|
|
2522
|
+
* Transforms the success value inside a TaskResult.
|
|
2625
2523
|
*/
|
|
2626
|
-
const map: <A, B>(f: (a: A) => B) =>
|
|
2524
|
+
const map: <E, A, B>(f: (a: A) => B) => (data: TaskResult<E, A>) => TaskResult<E, B>;
|
|
2627
2525
|
/**
|
|
2628
|
-
* Transforms the error
|
|
2629
|
-
*
|
|
2630
|
-
* @example
|
|
2631
|
-
* ```ts
|
|
2632
|
-
* pipe(Validation.failed("oops"), Validation.mapError(e => e.toUpperCase())); // Failed(["OOPS"])
|
|
2633
|
-
* ```
|
|
2526
|
+
* Transforms the error value inside a TaskResult.
|
|
2634
2527
|
*/
|
|
2635
|
-
const mapError: <E, F, A>(f: (e: E) => F) => (data:
|
|
2528
|
+
const mapError: <E, F, A>(f: (e: E) => F) => (data: TaskResult<E, A>) => TaskResult<F, A>;
|
|
2636
2529
|
/**
|
|
2637
|
-
*
|
|
2638
|
-
*
|
|
2639
|
-
*
|
|
2640
|
-
* @example
|
|
2641
|
-
* ```ts
|
|
2642
|
-
* const add = (a: number) => (b: number) => a + b;
|
|
2643
|
-
* pipe(
|
|
2644
|
-
* Validation.passed(add),
|
|
2645
|
-
* Validation.ap(Validation.passed(5)),
|
|
2646
|
-
* Validation.ap(Validation.passed(3))
|
|
2647
|
-
* ); // Passed(8)
|
|
2648
|
-
*
|
|
2649
|
-
* pipe(
|
|
2650
|
-
* Validation.passed(add),
|
|
2651
|
-
* Validation.ap(Validation.failed<string, number>("bad a")),
|
|
2652
|
-
* Validation.ap(Validation.failed<string, number>("bad b"))
|
|
2653
|
-
* ); // Failed(["bad a", "bad b"])
|
|
2654
|
-
* ```
|
|
2530
|
+
* Chains TaskResult computations. If the first succeeds, passes the value to f.
|
|
2531
|
+
* If the first fails, propagates the error.
|
|
2655
2532
|
*/
|
|
2656
|
-
const
|
|
2533
|
+
const chain: <E, A, B>(f: (a: A) => TaskResult<E, B>) => (data: TaskResult<E, A>) => TaskResult<E, B>;
|
|
2657
2534
|
/**
|
|
2658
|
-
* Extracts the value from a
|
|
2659
|
-
*
|
|
2660
|
-
* @example
|
|
2661
|
-
* ```ts
|
|
2662
|
-
* pipe(
|
|
2663
|
-
* Validation.passed(42),
|
|
2664
|
-
* Validation.fold(
|
|
2665
|
-
* errors => `Errors: ${errors.join(", ")}`,
|
|
2666
|
-
* value => `Value: ${value}`
|
|
2667
|
-
* )
|
|
2668
|
-
* );
|
|
2669
|
-
* ```
|
|
2535
|
+
* Extracts the value from a TaskResult by providing handlers for both cases.
|
|
2670
2536
|
*/
|
|
2671
|
-
const fold: <E, A, B>(
|
|
2537
|
+
const fold: <E, A, B>(onErr: (e: E) => B, onOk: (a: A) => B) => (data: TaskResult<E, A>) => Task<B>;
|
|
2672
2538
|
/**
|
|
2673
|
-
* Pattern matches on a
|
|
2674
|
-
*
|
|
2675
|
-
* @example
|
|
2676
|
-
* ```ts
|
|
2677
|
-
* pipe(
|
|
2678
|
-
* validation,
|
|
2679
|
-
* Validation.match({
|
|
2680
|
-
* passed: value => `Got ${value}`,
|
|
2681
|
-
* failed: errors => `Failed: ${errors.join(", ")}`
|
|
2682
|
-
* })
|
|
2683
|
-
* );
|
|
2684
|
-
* ```
|
|
2539
|
+
* Pattern matches on a TaskResult, returning a Task of the result.
|
|
2685
2540
|
*/
|
|
2686
2541
|
const match: <E, A, B>(cases: {
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
}) => (data:
|
|
2690
|
-
/**
|
|
2691
|
-
* Returns the success value or a default value if the Validation is failed.
|
|
2692
|
-
* The default can be a different type, widening the result to `A | B`.
|
|
2693
|
-
*
|
|
2694
|
-
* @example
|
|
2695
|
-
* ```ts
|
|
2696
|
-
* pipe(Validation.passed(5), Validation.getOrElse(() => 0)); // 5
|
|
2697
|
-
* pipe(Validation.failed("oops"), Validation.getOrElse(() => 0)); // 0
|
|
2698
|
-
* pipe(Validation.failed("oops"), Validation.getOrElse(() => null)); // null — typed as number | null
|
|
2699
|
-
* ```
|
|
2700
|
-
*/
|
|
2701
|
-
const getOrElse: <E, A, B>(defaultValue: () => B) => (data: Validation<E, A>) => A | B;
|
|
2542
|
+
err: (e: E) => B;
|
|
2543
|
+
ok: (a: A) => B;
|
|
2544
|
+
}) => (data: TaskResult<E, A>) => Task<B>;
|
|
2702
2545
|
/**
|
|
2703
|
-
*
|
|
2704
|
-
*
|
|
2705
|
-
* @example
|
|
2706
|
-
* ```ts
|
|
2707
|
-
* pipe(
|
|
2708
|
-
* Validation.passed(5),
|
|
2709
|
-
* Validation.tap(n => console.log("Value:", n)),
|
|
2710
|
-
* Validation.map(n => n * 2)
|
|
2711
|
-
* );
|
|
2712
|
-
* ```
|
|
2546
|
+
* Recovers from an error by providing a fallback TaskResult.
|
|
2547
|
+
* The fallback can produce a different success type, widening the result to `TaskResult<E, A | B>`.
|
|
2713
2548
|
*/
|
|
2714
|
-
const
|
|
2549
|
+
const recover: <E, A, B>(fallback: (e: E) => TaskResult<E, B>) => (data: TaskResult<E, A>) => TaskResult<E, A | B>;
|
|
2715
2550
|
/**
|
|
2716
|
-
*
|
|
2717
|
-
*
|
|
2718
|
-
*
|
|
2719
|
-
* @example
|
|
2720
|
-
* ```ts
|
|
2721
|
-
* pipe(
|
|
2722
|
-
* Validation.failed("Name required"),
|
|
2723
|
-
* Validation.tapError(errors => console.error("validation failed:", errors)),
|
|
2724
|
-
* Validation.map(toUser)
|
|
2725
|
-
* );
|
|
2726
|
-
* ```
|
|
2551
|
+
* Returns the success value or a default value if the TaskResult is an error.
|
|
2552
|
+
* The default can be a different type, widening the result to `Task<A | B>`.
|
|
2727
2553
|
*/
|
|
2728
|
-
const
|
|
2554
|
+
const getOrElse: <E, A, B>(defaultValue: () => B) => (data: TaskResult<E, A>) => Task<A | B>;
|
|
2729
2555
|
/**
|
|
2730
|
-
*
|
|
2731
|
-
*
|
|
2732
|
-
* The fallback can produce a different success type, widening the result to `Validation<E, A | B>`.
|
|
2556
|
+
* Executes a side effect on the success value without changing the TaskResult.
|
|
2557
|
+
* Useful for logging or debugging.
|
|
2733
2558
|
*/
|
|
2734
|
-
const
|
|
2559
|
+
const tap: <E, A>(f: (a: A) => void) => (data: TaskResult<E, A>) => TaskResult<E, A>;
|
|
2735
2560
|
/**
|
|
2736
|
-
*
|
|
2737
|
-
*
|
|
2561
|
+
* Executes a side effect on the error value without changing the TaskResult.
|
|
2562
|
+
* Useful for logging or reporting async errors.
|
|
2738
2563
|
*
|
|
2739
2564
|
* @example
|
|
2740
2565
|
* ```ts
|
|
2741
2566
|
* pipe(
|
|
2742
|
-
*
|
|
2743
|
-
*
|
|
2744
|
-
*
|
|
2567
|
+
* fetchUser(id),
|
|
2568
|
+
* TaskResult.tapError(e => console.error("fetch failed:", e)),
|
|
2569
|
+
* TaskResult.chain(saveToCache),
|
|
2570
|
+
* )
|
|
2745
2571
|
* ```
|
|
2746
2572
|
*/
|
|
2747
|
-
const
|
|
2573
|
+
const tapError: <E, A>(f: (e: E) => void) => (data: TaskResult<E, A>) => TaskResult<E, A>;
|
|
2748
2574
|
/**
|
|
2749
|
-
*
|
|
2750
|
-
*
|
|
2751
|
-
*
|
|
2752
|
-
* @example
|
|
2753
|
-
* ```ts
|
|
2754
|
-
* Validation.toResult(Validation.passed(42)); // Ok(42)
|
|
2755
|
-
* Validation.toResult(Validation.failed("oops")); // Err(["oops"])
|
|
2756
|
-
* ```
|
|
2575
|
+
* Applies a function wrapped in a TaskResult to a value wrapped in a TaskResult.
|
|
2576
|
+
* Both Tasks run in parallel.
|
|
2757
2577
|
*/
|
|
2758
|
-
const
|
|
2578
|
+
const ap: <E, A>(arg: TaskResult<E, A>) => <B>(data: TaskResult<E, (a: A) => B>) => TaskResult<E, B>;
|
|
2759
2579
|
/**
|
|
2760
|
-
*
|
|
2761
|
-
*
|
|
2580
|
+
* Executes a `TaskResult` with an optional signal, returning `Promise<Result<E, A>>`.
|
|
2581
|
+
* Use as a terminal step in a `pipe` chain.
|
|
2762
2582
|
*
|
|
2763
2583
|
* @example
|
|
2764
2584
|
* ```ts
|
|
2765
|
-
*
|
|
2766
|
-
*
|
|
2585
|
+
* const controller = new AbortController();
|
|
2586
|
+
* const result = await pipe(
|
|
2587
|
+
* fetchUser("42"),
|
|
2588
|
+
* TaskResult.chain(user => fetchPosts(user.id)),
|
|
2589
|
+
* TaskResult.run(controller.signal),
|
|
2590
|
+
* );
|
|
2591
|
+
* if (Result.isOk(result)) render(result.value);
|
|
2767
2592
|
* ```
|
|
2768
2593
|
*/
|
|
2769
|
-
const
|
|
2594
|
+
const run: (signal?: AbortSignal) => <E, A>(task: TaskResult<E, A>) => Promise<Result<E, A>>;
|
|
2770
2595
|
/**
|
|
2771
|
-
* Converts a
|
|
2772
|
-
*
|
|
2773
|
-
* Useful when bridging from error-short-circuiting `Result` pipelines into
|
|
2774
|
-
* error-accumulating `Validation` pipelines.
|
|
2596
|
+
* Converts a TaskResult value into an object containing a single property.
|
|
2597
|
+
* Initiates the pipeline accumulator record.
|
|
2775
2598
|
*
|
|
2776
2599
|
* @example
|
|
2777
2600
|
* ```ts
|
|
2778
|
-
*
|
|
2779
|
-
* Validation.fromResult(Result.err("bad")); // Failed(["bad"])
|
|
2601
|
+
* pipe(TaskResult.ok(42), TaskResult.bindTo("value")); // TaskResult({ value: 42 })
|
|
2780
2602
|
* ```
|
|
2781
2603
|
*/
|
|
2782
|
-
const
|
|
2604
|
+
const bindTo: <K extends string>(key: K) => <E, A>(data: TaskResult<E, A>) => TaskResult<E, { [P in K]: A; }>;
|
|
2783
2605
|
/**
|
|
2784
|
-
*
|
|
2785
|
-
* If both are Passed, returns Passed with both values as a tuple.
|
|
2786
|
-
* If either is Failed, accumulates errors from both sides.
|
|
2606
|
+
* Evaluates a new TaskResult using the current accumulator and attaches the output to a new key.
|
|
2787
2607
|
*
|
|
2788
2608
|
* @example
|
|
2789
2609
|
* ```ts
|
|
2790
|
-
*
|
|
2791
|
-
*
|
|
2792
|
-
*
|
|
2793
|
-
* ); //
|
|
2794
|
-
*
|
|
2795
|
-
* Validation.product(
|
|
2796
|
-
* Validation.failed("Name required"),
|
|
2797
|
-
* Validation.failed("Age must be >= 0")
|
|
2798
|
-
* ); // Failed(["Name required", "Age must be >= 0"])
|
|
2610
|
+
* pipe(
|
|
2611
|
+
* TaskResult.ok({ a: 1 }),
|
|
2612
|
+
* TaskResult.bind("b", ({ a }) => TaskResult.ok(a + 1))
|
|
2613
|
+
* ); // TaskResult({ a: 1, b: 2 })
|
|
2799
2614
|
* ```
|
|
2800
2615
|
*/
|
|
2801
|
-
const
|
|
2616
|
+
const bind: <K extends string, E, A, B>(key: K, f: (a: A) => TaskResult<E, B>) => (data: TaskResult<E, A>) => TaskResult<E, A & { [P in K]: B; }>;
|
|
2802
2617
|
/**
|
|
2803
|
-
* Combines a
|
|
2804
|
-
*
|
|
2805
|
-
*
|
|
2618
|
+
* Combines a record of TaskResults into a single TaskResult of a record.
|
|
2619
|
+
* Evaluates all tasks in parallel, forwarding the AbortSignal down to each sub-task.
|
|
2620
|
+
* Returns the first Err encountered in key order.
|
|
2806
2621
|
*
|
|
2807
2622
|
* @example
|
|
2808
2623
|
* ```ts
|
|
2809
|
-
*
|
|
2810
|
-
*
|
|
2811
|
-
*
|
|
2812
|
-
*
|
|
2813
|
-
* ]);
|
|
2814
|
-
* // Passed([name, email, age]) or Failed([...all errors])
|
|
2624
|
+
* TaskResult.struct({
|
|
2625
|
+
* name: TaskResult.ok("Alice"),
|
|
2626
|
+
* age: TaskResult.ok(30)
|
|
2627
|
+
* }); // TaskResult({ name: "Alice", age: 30 })
|
|
2815
2628
|
* ```
|
|
2816
2629
|
*/
|
|
2817
|
-
const
|
|
2630
|
+
const struct: <E, R extends Record<string, any>>(fields: { [K in keyof R]: TaskResult<E, R[K]>; }) => TaskResult<E, R>;
|
|
2818
2631
|
}
|
|
2819
2632
|
|
|
2820
2633
|
/**
|
|
@@ -3328,4 +3141,329 @@ declare namespace Tuple {
|
|
|
3328
3141
|
const tap: <A, B>(f: (a: A, b: B) => void) => (tuple: Tuple<A, B>) => Tuple<A, B>;
|
|
3329
3142
|
}
|
|
3330
3143
|
|
|
3144
|
+
type Passed<A> = WithKind<"Passed"> & WithValue<A>;
|
|
3145
|
+
type Failed<E> = WithKind<"Failed"> & WithErrors<E>;
|
|
3146
|
+
/**
|
|
3147
|
+
* Validation represents a value that is either passed with a success value,
|
|
3148
|
+
* or failed with accumulated errors.
|
|
3149
|
+
* Unlike Result, Validation can accumulate multiple errors instead of short-circuiting.
|
|
3150
|
+
*
|
|
3151
|
+
* Use Validation when you need to collect all errors (e.g., form validation).
|
|
3152
|
+
* Use Result when you want to fail fast on the first error.
|
|
3153
|
+
*
|
|
3154
|
+
* @example
|
|
3155
|
+
* ```ts
|
|
3156
|
+
* const validateName = (name: string): Validation<string, string> =>
|
|
3157
|
+
* name.length > 0 ? Validation.passed(name) : Validation.failed("Name is required");
|
|
3158
|
+
*
|
|
3159
|
+
* const validateAge = (age: number): Validation<string, number> =>
|
|
3160
|
+
* age >= 0 ? Validation.passed(age) : Validation.failed("Age must be positive");
|
|
3161
|
+
*
|
|
3162
|
+
* // Accumulates all errors using ap
|
|
3163
|
+
* pipe(
|
|
3164
|
+
* Validation.passed((name: string) => (age: number) => ({ name, age })),
|
|
3165
|
+
* Validation.ap(validateName("")),
|
|
3166
|
+
* Validation.ap(validateAge(-1))
|
|
3167
|
+
* );
|
|
3168
|
+
* // Failed(["Name is required", "Age must be positive"])
|
|
3169
|
+
* ```
|
|
3170
|
+
*/
|
|
3171
|
+
type Validation<E, A> = Passed<A> | Failed<E>;
|
|
3172
|
+
declare namespace Validation {
|
|
3173
|
+
/**
|
|
3174
|
+
* Wraps a value in a passed Validation.
|
|
3175
|
+
*
|
|
3176
|
+
* @example
|
|
3177
|
+
* ```ts
|
|
3178
|
+
* Validation.passed(42); // Passed(42)
|
|
3179
|
+
* ```
|
|
3180
|
+
*/
|
|
3181
|
+
const passed: <E, A>(value: A) => Validation<E, A>;
|
|
3182
|
+
/**
|
|
3183
|
+
* Creates a failed Validation from a single error.
|
|
3184
|
+
*
|
|
3185
|
+
* @example
|
|
3186
|
+
* ```ts
|
|
3187
|
+
* Validation.failed("Invalid input");
|
|
3188
|
+
* ```
|
|
3189
|
+
*/
|
|
3190
|
+
const failed: <E>(error: E) => Failed<E>;
|
|
3191
|
+
/**
|
|
3192
|
+
* Creates a failed Validation from multiple errors.
|
|
3193
|
+
*
|
|
3194
|
+
* @example
|
|
3195
|
+
* ```ts
|
|
3196
|
+
* Validation.failedAll(["Invalid input"]);
|
|
3197
|
+
* ```
|
|
3198
|
+
*/
|
|
3199
|
+
const failedAll: <E>(errors: NonEmptyList<E>) => Failed<E>;
|
|
3200
|
+
/**
|
|
3201
|
+
* Type guard that checks if a Validation is passed.
|
|
3202
|
+
*/
|
|
3203
|
+
const isPassed: <E, A>(data: Validation<E, A>) => data is Passed<A>;
|
|
3204
|
+
/**
|
|
3205
|
+
* Type guard that checks if a Validation is failed.
|
|
3206
|
+
*/
|
|
3207
|
+
const isFailed: <E, A>(data: Validation<E, A>) => data is Failed<E>;
|
|
3208
|
+
/**
|
|
3209
|
+
* Creates a Validation from a predicate applied to a value.
|
|
3210
|
+
* Returns Passed if the predicate passes, Failed from `onFalse` otherwise.
|
|
3211
|
+
*
|
|
3212
|
+
* @example
|
|
3213
|
+
* ```ts
|
|
3214
|
+
* const validateName = Validation.fromPredicate(
|
|
3215
|
+
* (s: string) => s.length > 0,
|
|
3216
|
+
* () => "Name is required"
|
|
3217
|
+
* );
|
|
3218
|
+
*
|
|
3219
|
+
* validateName("Alice"); // Passed("Alice")
|
|
3220
|
+
* validateName(""); // Failed(["Name is required"])
|
|
3221
|
+
* ```
|
|
3222
|
+
*/
|
|
3223
|
+
const fromPredicate: <E, A>(pred: (a: A) => boolean, onFalse: (a: A) => E) => (a: A) => Validation<E, A>;
|
|
3224
|
+
/**
|
|
3225
|
+
* Creates a Validation from a nullable value.
|
|
3226
|
+
* If the value is null or undefined, returns Failed with the error from onNull.
|
|
3227
|
+
* Otherwise, returns Passed.
|
|
3228
|
+
*
|
|
3229
|
+
* @example
|
|
3230
|
+
* ```ts
|
|
3231
|
+
* pipe(null, Validation.fromNullable(() => "is null")); // Failed(["is null"])
|
|
3232
|
+
* pipe(42, Validation.fromNullable(() => "is null")); // Passed(42)
|
|
3233
|
+
* ```
|
|
3234
|
+
*/
|
|
3235
|
+
const fromNullable: <E>(onNull: () => E) => <A>(value: A | null | undefined) => Validation<E, A>;
|
|
3236
|
+
/**
|
|
3237
|
+
* Creates a Validation from a Maybe.
|
|
3238
|
+
* If the Maybe is None, returns Failed with the error from onNone.
|
|
3239
|
+
* Otherwise, returns Passed.
|
|
3240
|
+
*
|
|
3241
|
+
* @example
|
|
3242
|
+
* ```ts
|
|
3243
|
+
* pipe(Maybe.none(), Validation.fromMaybe(() => "is none")); // Failed(["is none"])
|
|
3244
|
+
* pipe(Maybe.some(42), Validation.fromMaybe(() => "is none")); // Passed(42)
|
|
3245
|
+
* ```
|
|
3246
|
+
*/
|
|
3247
|
+
const fromMaybe: <E>(onNone: () => E) => <A>(maybe: Maybe<A>) => Validation<E, A>;
|
|
3248
|
+
/**
|
|
3249
|
+
* Transforms the success value inside a Validation.
|
|
3250
|
+
*
|
|
3251
|
+
* @example
|
|
3252
|
+
* ```ts
|
|
3253
|
+
* pipe(Validation.passed(5), Validation.map(n => n * 2)); // Passed(10)
|
|
3254
|
+
* pipe(Validation.failed("oops"), Validation.map(n => n * 2)); // Failed(["oops"])
|
|
3255
|
+
* ```
|
|
3256
|
+
*/
|
|
3257
|
+
const map: <A, B>(f: (a: A) => B) => <E>(data: Validation<E, A>) => Validation<E, B>;
|
|
3258
|
+
/**
|
|
3259
|
+
* Transforms the error list inside a Validation.
|
|
3260
|
+
*
|
|
3261
|
+
* @example
|
|
3262
|
+
* ```ts
|
|
3263
|
+
* pipe(Validation.failed("oops"), Validation.mapError(e => e.toUpperCase())); // Failed(["OOPS"])
|
|
3264
|
+
* ```
|
|
3265
|
+
*/
|
|
3266
|
+
const mapError: <E, F, A>(f: (e: E) => F) => (data: Validation<E, A>) => Validation<F, A>;
|
|
3267
|
+
/**
|
|
3268
|
+
* Applies a function wrapped in a Validation to a value wrapped in a Validation.
|
|
3269
|
+
* Accumulates errors from both sides.
|
|
3270
|
+
*
|
|
3271
|
+
* @example
|
|
3272
|
+
* ```ts
|
|
3273
|
+
* const add = (a: number) => (b: number) => a + b;
|
|
3274
|
+
* pipe(
|
|
3275
|
+
* Validation.passed(add),
|
|
3276
|
+
* Validation.ap(Validation.passed(5)),
|
|
3277
|
+
* Validation.ap(Validation.passed(3))
|
|
3278
|
+
* ); // Passed(8)
|
|
3279
|
+
*
|
|
3280
|
+
* pipe(
|
|
3281
|
+
* Validation.passed(add),
|
|
3282
|
+
* Validation.ap(Validation.failed<string, number>("bad a")),
|
|
3283
|
+
* Validation.ap(Validation.failed<string, number>("bad b"))
|
|
3284
|
+
* ); // Failed(["bad a", "bad b"])
|
|
3285
|
+
* ```
|
|
3286
|
+
*/
|
|
3287
|
+
const ap: <E, A>(arg: Validation<E, A>) => <B>(data: Validation<E, (a: A) => B>) => Validation<E, B>;
|
|
3288
|
+
/**
|
|
3289
|
+
* Extracts the value from a Validation by providing handlers for both cases.
|
|
3290
|
+
*
|
|
3291
|
+
* @example
|
|
3292
|
+
* ```ts
|
|
3293
|
+
* pipe(
|
|
3294
|
+
* Validation.passed(42),
|
|
3295
|
+
* Validation.fold(
|
|
3296
|
+
* errors => `Errors: ${errors.join(", ")}`,
|
|
3297
|
+
* value => `Value: ${value}`
|
|
3298
|
+
* )
|
|
3299
|
+
* );
|
|
3300
|
+
* ```
|
|
3301
|
+
*/
|
|
3302
|
+
const fold: <E, A, B>(onFailed: (errors: NonEmptyList<E>) => B, onPassed: (a: A) => B) => (data: Validation<E, A>) => B;
|
|
3303
|
+
/**
|
|
3304
|
+
* Pattern matches on a Validation, returning the result of the matching case.
|
|
3305
|
+
*
|
|
3306
|
+
* @example
|
|
3307
|
+
* ```ts
|
|
3308
|
+
* pipe(
|
|
3309
|
+
* validation,
|
|
3310
|
+
* Validation.match({
|
|
3311
|
+
* passed: value => `Got ${value}`,
|
|
3312
|
+
* failed: errors => `Failed: ${errors.join(", ")}`
|
|
3313
|
+
* })
|
|
3314
|
+
* );
|
|
3315
|
+
* ```
|
|
3316
|
+
*/
|
|
3317
|
+
const match: <E, A, B>(cases: {
|
|
3318
|
+
passed: (a: A) => B;
|
|
3319
|
+
failed: (errors: NonEmptyList<E>) => B;
|
|
3320
|
+
}) => (data: Validation<E, A>) => B;
|
|
3321
|
+
/**
|
|
3322
|
+
* Returns the success value or a default value if the Validation is failed.
|
|
3323
|
+
* The default can be a different type, widening the result to `A | B`.
|
|
3324
|
+
*
|
|
3325
|
+
* @example
|
|
3326
|
+
* ```ts
|
|
3327
|
+
* pipe(Validation.passed(5), Validation.getOrElse(() => 0)); // 5
|
|
3328
|
+
* pipe(Validation.failed("oops"), Validation.getOrElse(() => 0)); // 0
|
|
3329
|
+
* pipe(Validation.failed("oops"), Validation.getOrElse(() => null)); // null — typed as number | null
|
|
3330
|
+
* ```
|
|
3331
|
+
*/
|
|
3332
|
+
const getOrElse: <E, A, B>(defaultValue: () => B) => (data: Validation<E, A>) => A | B;
|
|
3333
|
+
/**
|
|
3334
|
+
* Executes a side effect on the success value without changing the Validation.
|
|
3335
|
+
*
|
|
3336
|
+
* @example
|
|
3337
|
+
* ```ts
|
|
3338
|
+
* pipe(
|
|
3339
|
+
* Validation.passed(5),
|
|
3340
|
+
* Validation.tap(n => console.log("Value:", n)),
|
|
3341
|
+
* Validation.map(n => n * 2)
|
|
3342
|
+
* );
|
|
3343
|
+
* ```
|
|
3344
|
+
*/
|
|
3345
|
+
const tap: <E, A>(f: (a: A) => void) => (data: Validation<E, A>) => Validation<E, A>;
|
|
3346
|
+
/**
|
|
3347
|
+
* Executes a side effect on the accumulated errors without changing the Validation.
|
|
3348
|
+
* Useful for logging or reporting validation failures.
|
|
3349
|
+
*
|
|
3350
|
+
* @example
|
|
3351
|
+
* ```ts
|
|
3352
|
+
* pipe(
|
|
3353
|
+
* Validation.failed("Name required"),
|
|
3354
|
+
* Validation.tapError(errors => console.error("validation failed:", errors)),
|
|
3355
|
+
* Validation.map(toUser)
|
|
3356
|
+
* );
|
|
3357
|
+
* ```
|
|
3358
|
+
*/
|
|
3359
|
+
const tapError: <E, A>(f: (errors: NonEmptyList<E>) => void) => (data: Validation<E, A>) => Validation<E, A>;
|
|
3360
|
+
/**
|
|
3361
|
+
* Recovers from a Failed state by providing a fallback Validation.
|
|
3362
|
+
* The fallback receives the accumulated error list so callers can inspect which errors occurred.
|
|
3363
|
+
* The fallback can produce a different success type, widening the result to `Validation<E, A | B>`.
|
|
3364
|
+
*/
|
|
3365
|
+
const recover: <E, A, B>(fallback: (errors: NonEmptyList<E>) => Validation<E, B>) => (data: Validation<E, A>) => Validation<E, A | B>;
|
|
3366
|
+
/**
|
|
3367
|
+
* Recovers from a Failed state unless `isBlocked` returns true for any of the accumulated errors.
|
|
3368
|
+
* The fallback can produce a different success type, widening the result to `Validation<E, A | B>`.
|
|
3369
|
+
*
|
|
3370
|
+
* @example
|
|
3371
|
+
* ```ts
|
|
3372
|
+
* pipe(
|
|
3373
|
+
* Validation.failed("field-error"),
|
|
3374
|
+
* Validation.recoverUnless(e => e === "fatal", () => Validation.passed(0))
|
|
3375
|
+
* ); // Passed(0)
|
|
3376
|
+
* ```
|
|
3377
|
+
*/
|
|
3378
|
+
const recoverUnless: <E, A, B>(isBlocked: (e: E) => boolean, fallback: () => Validation<E, B>) => (data: Validation<E, A>) => Validation<E, A | B>;
|
|
3379
|
+
/**
|
|
3380
|
+
* Converts a Validation to a Result.
|
|
3381
|
+
* Passed becomes Ok, Failed becomes Err with the accumulated error list.
|
|
3382
|
+
*
|
|
3383
|
+
* @example
|
|
3384
|
+
* ```ts
|
|
3385
|
+
* Validation.toResult(Validation.passed(42)); // Ok(42)
|
|
3386
|
+
* Validation.toResult(Validation.failed("oops")); // Err(["oops"])
|
|
3387
|
+
* ```
|
|
3388
|
+
*/
|
|
3389
|
+
const toResult: <E, A>(data: Validation<E, A>) => Result<NonEmptyList<E>, A>;
|
|
3390
|
+
/**
|
|
3391
|
+
* Converts a Validation to a Maybe. `Passed` becomes `Some`; `Failed` becomes `None`
|
|
3392
|
+
* (errors are discarded).
|
|
3393
|
+
*
|
|
3394
|
+
* @example
|
|
3395
|
+
* ```ts
|
|
3396
|
+
* Validation.toMaybe(Validation.passed(42)); // Some(42)
|
|
3397
|
+
* Validation.toMaybe(Validation.failed("bad")); // None
|
|
3398
|
+
* ```
|
|
3399
|
+
*/
|
|
3400
|
+
const toMaybe: <E, A>(data: Validation<E, A>) => Maybe<A>;
|
|
3401
|
+
/**
|
|
3402
|
+
* Converts a `Result` to a `Validation`. `Ok` becomes `Passed`; `Err(e)` becomes `Failed([e])`.
|
|
3403
|
+
*
|
|
3404
|
+
* Useful when bridging from error-short-circuiting `Result` pipelines into
|
|
3405
|
+
* error-accumulating `Validation` pipelines.
|
|
3406
|
+
*
|
|
3407
|
+
* @example
|
|
3408
|
+
* ```ts
|
|
3409
|
+
* Validation.fromResult(Result.ok(42)); // Passed(42)
|
|
3410
|
+
* Validation.fromResult(Result.err("bad")); // Failed(["bad"])
|
|
3411
|
+
* ```
|
|
3412
|
+
*/
|
|
3413
|
+
const fromResult: <E, A>(data: Result<E, A>) => Validation<E, A>;
|
|
3414
|
+
/**
|
|
3415
|
+
* Combines two independent Validation instances into a tuple.
|
|
3416
|
+
* If both are Passed, returns Passed with both values as a tuple.
|
|
3417
|
+
* If either is Failed, accumulates errors from both sides.
|
|
3418
|
+
*
|
|
3419
|
+
* @example
|
|
3420
|
+
* ```ts
|
|
3421
|
+
* Validation.product(
|
|
3422
|
+
* Validation.passed("alice"),
|
|
3423
|
+
* Validation.passed(30)
|
|
3424
|
+
* ); // Passed(["alice", 30])
|
|
3425
|
+
*
|
|
3426
|
+
* Validation.product(
|
|
3427
|
+
* Validation.failed("Name required"),
|
|
3428
|
+
* Validation.failed("Age must be >= 0")
|
|
3429
|
+
* ); // Failed(["Name required", "Age must be >= 0"])
|
|
3430
|
+
* ```
|
|
3431
|
+
*/
|
|
3432
|
+
const product: <E, A, B>(first: Validation<E, A>, second: Validation<E, B>) => Validation<E, readonly [A, B]>;
|
|
3433
|
+
/**
|
|
3434
|
+
* Combines a non-empty list of Validation instances, accumulating all errors.
|
|
3435
|
+
* If all are Passed, returns Passed with all values collected into an array.
|
|
3436
|
+
* If any are Failed, returns Failed with all accumulated errors.
|
|
3437
|
+
*
|
|
3438
|
+
* @example
|
|
3439
|
+
* ```ts
|
|
3440
|
+
* Validation.productAll([
|
|
3441
|
+
* validateName(name),
|
|
3442
|
+
* validateEmail(email),
|
|
3443
|
+
* validateAge(age)
|
|
3444
|
+
* ]);
|
|
3445
|
+
* // Passed([name, email, age]) or Failed([...all errors])
|
|
3446
|
+
* ```
|
|
3447
|
+
*/
|
|
3448
|
+
const productAll: <E, A>(data: NonEmptyList<Validation<E, A>>) => Validation<E, readonly A[]>;
|
|
3449
|
+
/**
|
|
3450
|
+
* Combines a record of Validations into a single Validation of a record.
|
|
3451
|
+
* Accumulates all failed branches' errors.
|
|
3452
|
+
*
|
|
3453
|
+
* @example
|
|
3454
|
+
* ```ts
|
|
3455
|
+
* Validation.struct({
|
|
3456
|
+
* name: Validation.passed("Alice"),
|
|
3457
|
+
* age: Validation.passed(30)
|
|
3458
|
+
* }); // Passed({ name: "Alice", age: 30 })
|
|
3459
|
+
*
|
|
3460
|
+
* Validation.struct({
|
|
3461
|
+
* name: Validation.failed("Name required"),
|
|
3462
|
+
* age: Validation.failed("Age must be >= 0")
|
|
3463
|
+
* }); // Failed(["Name required", "Age must be >= 0"])
|
|
3464
|
+
* ```
|
|
3465
|
+
*/
|
|
3466
|
+
const struct: <E, R extends Record<string, any>>(fields: { [K in keyof R]: Validation<E, R[K]>; }) => Validation<E, R>;
|
|
3467
|
+
}
|
|
3468
|
+
|
|
3331
3469
|
export { Combinable, Deferred, type Failed, type Failure, Lazy, Lens, type Loading, Logged, Maybe, type NotAsked, Op, Optional, type Passed, Predicate, Reader, Refinement, RemoteData, Resource, Result, State, type Success, Task, TaskMaybe, TaskResult, TaskValidation, These, type TheseBoth, type TheseFirst, type TheseSecond, Tuple, Validation };
|