@nlozgachev/pipelined 0.62.0 → 0.64.0
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 +14 -14
- package/dist/{Duration-B8joKzro.d.cts → Duration-DeyxG6VQ.d.cts} +20 -20
- package/dist/{Duration-B8joKzro.d.ts → Duration-DeyxG6VQ.d.ts} +20 -20
- package/dist/{InternalTypes-LdhLQx3N.d.ts → InternalTypes-CCXa8Kvr.d.ts} +11 -11
- package/dist/{InternalTypes-DuK_XpTi.d.cts → InternalTypes-GFn4RTwD.d.cts} +11 -11
- package/dist/{Validation-DZLizBZ0.d.ts → Task-9SJCMtG4.d.ts} +690 -1395
- package/dist/{Validation-DC3uUizM.d.cts → Task-C_goFYQ1.d.cts} +690 -1395
- package/dist/composition.cjs +216 -95
- package/dist/composition.d.cts +8 -76
- package/dist/composition.d.ts +8 -76
- package/dist/composition.mjs +216 -95
- package/dist/core.cjs +4905 -1028
- package/dist/core.d.cts +371 -773
- package/dist/core.d.ts +371 -773
- package/dist/core.mjs +4905 -1028
- package/dist/data.cjs +3313 -1242
- package/dist/data.d.cts +676 -1823
- package/dist/data.d.ts +676 -1823
- package/dist/data.mjs +3309 -1239
- package/dist/index.cjs +7270 -2216
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.mjs +7269 -2216
- package/dist/types.cjs +175 -31
- package/dist/types.d.cts +6 -6
- package/dist/types.d.ts +6 -6
- package/dist/types.mjs +175 -31
- package/package.json +24 -13
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { h as WithKind, o as WithValue, e as WithError, a as NonEmptyArr,
|
|
2
|
-
import { D as Duration } from './Duration-
|
|
1
|
+
import { h as WithKind, o as WithValue, e as WithError, a as NonEmptyArr, f as WithErrors, D as Deferred, T as Thenable } from './InternalTypes-CCXa8Kvr.js';
|
|
2
|
+
import { D as Duration } from './Duration-DeyxG6VQ.js';
|
|
3
3
|
import { RetryPolicy } from './types.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -16,7 +16,7 @@ import { RetryPolicy } from './types.js';
|
|
|
16
16
|
* ```
|
|
17
17
|
*/
|
|
18
18
|
type Equality<A> = (a: A, b: A) => boolean;
|
|
19
|
-
declare
|
|
19
|
+
declare const Equality: {
|
|
20
20
|
/**
|
|
21
21
|
* Equality for strings. Case-sensitive.
|
|
22
22
|
*
|
|
@@ -26,7 +26,7 @@ declare namespace Equality {
|
|
|
26
26
|
* Equality.string("hello", "Hello"); // false
|
|
27
27
|
* ```
|
|
28
28
|
*/
|
|
29
|
-
|
|
29
|
+
string: Equality<string>;
|
|
30
30
|
/**
|
|
31
31
|
* Equality for numbers. Uses strict equality.
|
|
32
32
|
*
|
|
@@ -35,7 +35,7 @@ declare namespace Equality {
|
|
|
35
35
|
* Equality.number(42, 42); // true
|
|
36
36
|
* ```
|
|
37
37
|
*/
|
|
38
|
-
|
|
38
|
+
number: Equality<number>;
|
|
39
39
|
/**
|
|
40
40
|
* Equality for booleans.
|
|
41
41
|
*
|
|
@@ -44,7 +44,7 @@ declare namespace Equality {
|
|
|
44
44
|
* Equality.boolean(true, true); // true
|
|
45
45
|
* ```
|
|
46
46
|
*/
|
|
47
|
-
|
|
47
|
+
boolean: Equality<boolean>;
|
|
48
48
|
/**
|
|
49
49
|
* Equality for `Date` values. Compares by numeric time value.
|
|
50
50
|
*
|
|
@@ -53,7 +53,7 @@ declare namespace Equality {
|
|
|
53
53
|
* Equality.date(new Date("2024-01-01"), new Date("2024-01-01")); // true
|
|
54
54
|
* ```
|
|
55
55
|
*/
|
|
56
|
-
|
|
56
|
+
date: Equality<Date>;
|
|
57
57
|
/**
|
|
58
58
|
* Lifts an element equality into an array equality. Two arrays are equal if they have the
|
|
59
59
|
* same length and every element pair is equal under `eq`.
|
|
@@ -63,7 +63,7 @@ declare namespace Equality {
|
|
|
63
63
|
* Equality.array(Equality.number)([1, 2, 3], [1, 2, 3]); // true
|
|
64
64
|
* ```
|
|
65
65
|
*/
|
|
66
|
-
|
|
66
|
+
array: <A>(eq: Equality<A>) => Equality<readonly A[]>;
|
|
67
67
|
/**
|
|
68
68
|
* Adapts an equality for type `A` into an equality for type `B` by extracting a field.
|
|
69
69
|
* Read as "equality by this field": `pipe(Equality.string, Equality.by(u => u.name))`.
|
|
@@ -75,7 +75,7 @@ declare namespace Equality {
|
|
|
75
75
|
* byId({ id: "p1", price: 9 }, { id: "p1", price: 12 }); // true
|
|
76
76
|
* ```
|
|
77
77
|
*/
|
|
78
|
-
|
|
78
|
+
by: <A, B>(f: (b: B) => A) => (eq: Equality<A>) => Equality<B>;
|
|
79
79
|
/**
|
|
80
80
|
* Combines two equalities with logical AND. Both must pass for two values to be considered equal.
|
|
81
81
|
* Data-last: the first equality is the data being piped.
|
|
@@ -86,7 +86,7 @@ declare namespace Equality {
|
|
|
86
86
|
* exact(userA, userB); // true only if name AND role match
|
|
87
87
|
* ```
|
|
88
88
|
*/
|
|
89
|
-
|
|
89
|
+
and: <A>(eq2: Equality<A>) => (eq1: Equality<A>) => Equality<A>;
|
|
90
90
|
/**
|
|
91
91
|
* Derives deep equality for a record from field-level `Equality` checkers.
|
|
92
92
|
*
|
|
@@ -98,7 +98,7 @@ declare namespace Equality {
|
|
|
98
98
|
* });
|
|
99
99
|
* ```
|
|
100
100
|
*/
|
|
101
|
-
|
|
101
|
+
struct: <R extends Record<string, unknown>>(fields: { [K in keyof R]: Equality<R[K]>; }) => Equality<R>;
|
|
102
102
|
/**
|
|
103
103
|
* Derives element-wise equality for a tuple from positional `Equality` checkers.
|
|
104
104
|
*
|
|
@@ -108,8 +108,8 @@ declare namespace Equality {
|
|
|
108
108
|
* pairEq(["a", 1], ["a", 1]); // true
|
|
109
109
|
* ```
|
|
110
110
|
*/
|
|
111
|
-
|
|
112
|
-
}
|
|
111
|
+
tuple: <T extends readonly unknown[]>(...equalities: { [K in keyof T]: Equality<T[K]>; }) => Equality<T>;
|
|
112
|
+
};
|
|
113
113
|
|
|
114
114
|
type Some<A> = WithKind<"Some"> & WithValue<A>;
|
|
115
115
|
type None = WithKind<"None">;
|
|
@@ -129,8 +129,8 @@ type None = WithKind<"None">;
|
|
|
129
129
|
* ```
|
|
130
130
|
*/
|
|
131
131
|
type Maybe<T> = Some<T> | None;
|
|
132
|
-
declare
|
|
133
|
-
|
|
132
|
+
declare const Maybe: {
|
|
133
|
+
make: {
|
|
134
134
|
/**
|
|
135
135
|
* Creates a Some containing the given value.
|
|
136
136
|
*
|
|
@@ -139,7 +139,7 @@ declare namespace Maybe {
|
|
|
139
139
|
* Maybe.make.some(42); // Some(42)
|
|
140
140
|
* ```
|
|
141
141
|
*/
|
|
142
|
-
|
|
142
|
+
some: <A>(value: A) => Some<A>;
|
|
143
143
|
/**
|
|
144
144
|
* Creates a None (empty Maybe).
|
|
145
145
|
*
|
|
@@ -148,9 +148,9 @@ declare namespace Maybe {
|
|
|
148
148
|
* Maybe.make.none(); // None
|
|
149
149
|
* ```
|
|
150
150
|
*/
|
|
151
|
-
|
|
152
|
-
}
|
|
153
|
-
|
|
151
|
+
none: () => None;
|
|
152
|
+
};
|
|
153
|
+
is: {
|
|
154
154
|
/**
|
|
155
155
|
* Type guard that checks if a Maybe is Some.
|
|
156
156
|
*
|
|
@@ -162,7 +162,7 @@ declare namespace Maybe {
|
|
|
162
162
|
* }
|
|
163
163
|
* ```
|
|
164
164
|
*/
|
|
165
|
-
|
|
165
|
+
some: <A>(data: Maybe<A>) => data is Some<A>;
|
|
166
166
|
/**
|
|
167
167
|
* Type guard that checks if a Maybe is None.
|
|
168
168
|
*
|
|
@@ -174,9 +174,9 @@ declare namespace Maybe {
|
|
|
174
174
|
* }
|
|
175
175
|
* ```
|
|
176
176
|
*/
|
|
177
|
-
|
|
178
|
-
}
|
|
179
|
-
|
|
177
|
+
none: <A>(data: Maybe<A>) => data is None;
|
|
178
|
+
};
|
|
179
|
+
to: {
|
|
180
180
|
/**
|
|
181
181
|
* Extracts the value from a Maybe, returning null if None.
|
|
182
182
|
*
|
|
@@ -186,7 +186,7 @@ declare namespace Maybe {
|
|
|
186
186
|
* Maybe.to.nullable(Maybe.make.none()); // null
|
|
187
187
|
* ```
|
|
188
188
|
*/
|
|
189
|
-
|
|
189
|
+
nullable: <A>(data: Maybe<A>) => A | null;
|
|
190
190
|
/**
|
|
191
191
|
* Extracts the value from a Maybe, returning undefined if None.
|
|
192
192
|
*
|
|
@@ -196,7 +196,7 @@ declare namespace Maybe {
|
|
|
196
196
|
* Maybe.to.undefined(Maybe.make.none()); // undefined
|
|
197
197
|
* ```
|
|
198
198
|
*/
|
|
199
|
-
|
|
199
|
+
undefined: <A>(data: Maybe<A>) => A | undefined;
|
|
200
200
|
/**
|
|
201
201
|
* Converts a Maybe to a Result.
|
|
202
202
|
* Some becomes Ok, None becomes Err with the provided error.
|
|
@@ -214,9 +214,9 @@ declare namespace Maybe {
|
|
|
214
214
|
* ); // Err("Value was missing")
|
|
215
215
|
* ```
|
|
216
216
|
*/
|
|
217
|
-
|
|
218
|
-
}
|
|
219
|
-
|
|
217
|
+
Result: <E>(onNone: () => E) => <A>(data: Maybe<A>) => Result<E, A>;
|
|
218
|
+
};
|
|
219
|
+
from: {
|
|
220
220
|
/**
|
|
221
221
|
* Creates a Maybe from a nullable value.
|
|
222
222
|
* Returns None if the value is null or undefined, Some otherwise.
|
|
@@ -227,7 +227,7 @@ declare namespace Maybe {
|
|
|
227
227
|
* Maybe.from.nullable(42); // Some(42)
|
|
228
228
|
* ```
|
|
229
229
|
*/
|
|
230
|
-
|
|
230
|
+
nullable: <A>(value: A | null | undefined) => Maybe<A>;
|
|
231
231
|
/**
|
|
232
232
|
* Creates a Maybe from a predicate applied to a value.
|
|
233
233
|
* Returns Some if the predicate passes, None otherwise.
|
|
@@ -241,7 +241,7 @@ declare namespace Maybe {
|
|
|
241
241
|
* pipe("", Maybe.from.Predicate((s: string) => s.length > 0)); // None
|
|
242
242
|
* ```
|
|
243
243
|
*/
|
|
244
|
-
|
|
244
|
+
Predicate: <A>(pred: (a: A) => boolean) => (a: A) => Maybe<A>;
|
|
245
245
|
/**
|
|
246
246
|
* Creates a Maybe from a Result.
|
|
247
247
|
* Ok becomes Some, Err becomes None (the error is discarded).
|
|
@@ -252,8 +252,8 @@ declare namespace Maybe {
|
|
|
252
252
|
* Maybe.from.Result(Result.make.err("oops")); // None
|
|
253
253
|
* ```
|
|
254
254
|
*/
|
|
255
|
-
|
|
256
|
-
}
|
|
255
|
+
Result: <E, A>(data: Result<E, A>) => Maybe<A>;
|
|
256
|
+
};
|
|
257
257
|
/**
|
|
258
258
|
* Transforms the value inside a Maybe if it exists.
|
|
259
259
|
*
|
|
@@ -263,7 +263,7 @@ declare namespace Maybe {
|
|
|
263
263
|
* pipe(Maybe.make.none(), Maybe.map(n => n * 2)); // None
|
|
264
264
|
* ```
|
|
265
265
|
*/
|
|
266
|
-
|
|
266
|
+
map: <A, B>(f: (a: A) => B) => (data: Maybe<A>) => Maybe<B>;
|
|
267
267
|
/**
|
|
268
268
|
* Chains Maybe computations. If the first is Some, passes the value to f.
|
|
269
269
|
* If the first is None, propagates None.
|
|
@@ -279,7 +279,7 @@ declare namespace Maybe {
|
|
|
279
279
|
* pipe(Maybe.make.some("abc"), Maybe.chain(parseNumber)); // None
|
|
280
280
|
* ```
|
|
281
281
|
*/
|
|
282
|
-
|
|
282
|
+
chain: <A, B>(f: (a: A) => Maybe<B>) => (data: Maybe<A>) => Maybe<B>;
|
|
283
283
|
/**
|
|
284
284
|
* Extracts the value from a Maybe by providing handlers for both cases.
|
|
285
285
|
*
|
|
@@ -294,7 +294,7 @@ declare namespace Maybe {
|
|
|
294
294
|
* ); // "Value: 5"
|
|
295
295
|
* ```
|
|
296
296
|
*/
|
|
297
|
-
|
|
297
|
+
fold: <A, B>(onNone: () => B, onSome: (a: A) => B) => (data: Maybe<A>) => B;
|
|
298
298
|
/**
|
|
299
299
|
* Pattern matches on a Maybe, returning the result of the matching case.
|
|
300
300
|
*
|
|
@@ -309,7 +309,7 @@ declare namespace Maybe {
|
|
|
309
309
|
* );
|
|
310
310
|
* ```
|
|
311
311
|
*/
|
|
312
|
-
|
|
312
|
+
match: <A, B>(cases: {
|
|
313
313
|
none: () => B;
|
|
314
314
|
some: (a: A) => B;
|
|
315
315
|
}) => (data: Maybe<A>) => B;
|
|
@@ -325,7 +325,7 @@ declare namespace Maybe {
|
|
|
325
325
|
* pipe(Maybe.make.none<string>(), Maybe.getOrElse(() => null)); // null — typed as string | null
|
|
326
326
|
* ```
|
|
327
327
|
*/
|
|
328
|
-
|
|
328
|
+
getOrElse: <B>(defaultValue: () => B) => <A>(data: Maybe<A>) => A | B;
|
|
329
329
|
/**
|
|
330
330
|
* Executes a side effect on the value without changing the Maybe.
|
|
331
331
|
* Useful for logging or debugging.
|
|
@@ -339,7 +339,7 @@ declare namespace Maybe {
|
|
|
339
339
|
* );
|
|
340
340
|
* ```
|
|
341
341
|
*/
|
|
342
|
-
|
|
342
|
+
tap: <A>(f: (a: A) => void) => (data: Maybe<A>) => Maybe<A>;
|
|
343
343
|
/**
|
|
344
344
|
* Filters a Maybe based on a predicate.
|
|
345
345
|
* Returns None if the predicate returns false or if the Maybe is already None.
|
|
@@ -350,7 +350,7 @@ declare namespace Maybe {
|
|
|
350
350
|
* pipe(Maybe.make.some(2), Maybe.filter(n => n > 3)); // None
|
|
351
351
|
* ```
|
|
352
352
|
*/
|
|
353
|
-
|
|
353
|
+
filter: <A>(predicate: (a: A) => boolean) => (data: Maybe<A>) => Maybe<A>;
|
|
354
354
|
/**
|
|
355
355
|
* Recovers from a None by providing a fallback Maybe.
|
|
356
356
|
* The fallback can produce a different type, widening the result to `Maybe<A | B>`.
|
|
@@ -361,7 +361,7 @@ declare namespace Maybe {
|
|
|
361
361
|
* pipe(Maybe.make.some(10), Maybe.recover(() => Maybe.make.some(42))); // Some(10)
|
|
362
362
|
* ```
|
|
363
363
|
*/
|
|
364
|
-
|
|
364
|
+
recover: <B>(fallback: () => Maybe<B>) => <A>(data: Maybe<A>) => Maybe<A | B>;
|
|
365
365
|
/**
|
|
366
366
|
* Applies a function wrapped in a Maybe to a value wrapped in a Maybe.
|
|
367
367
|
*
|
|
@@ -375,7 +375,7 @@ declare namespace Maybe {
|
|
|
375
375
|
* ); // Some(8)
|
|
376
376
|
* ```
|
|
377
377
|
*/
|
|
378
|
-
|
|
378
|
+
ap: <A>(arg: Maybe<A>) => <B>(data: Maybe<(a: A) => B>) => Maybe<B>;
|
|
379
379
|
/**
|
|
380
380
|
* Converts a Maybe value into an object containing a single property.
|
|
381
381
|
* Initiates the pipeline accumulator record.
|
|
@@ -385,7 +385,7 @@ declare namespace Maybe {
|
|
|
385
385
|
* pipe(Maybe.make.some(42), Maybe.bindTo("value")); // Some({ value: 42 })
|
|
386
386
|
* ```
|
|
387
387
|
*/
|
|
388
|
-
|
|
388
|
+
bindTo: <K extends string>(key: K) => <A>(data: Maybe<A>) => Maybe<{ [P in K]: A; }>;
|
|
389
389
|
/**
|
|
390
390
|
* Evaluates a new Maybe using the current accumulator and attaches the output to a new key.
|
|
391
391
|
*
|
|
@@ -397,7 +397,7 @@ declare namespace Maybe {
|
|
|
397
397
|
* ); // Some({ a: 1, b: 2 })
|
|
398
398
|
* ```
|
|
399
399
|
*/
|
|
400
|
-
|
|
400
|
+
bind: <K extends string, A, B>(key: K, f: (a: A) => Maybe<B>) => (data: Maybe<A>) => Maybe<A & { [P in K]: B; }>;
|
|
401
401
|
/**
|
|
402
402
|
* Combines a record of Maybes into a single Maybe of a record.
|
|
403
403
|
* Evaluates fields in key order and short-circuits on the first None.
|
|
@@ -410,7 +410,7 @@ declare namespace Maybe {
|
|
|
410
410
|
* }); // Some({ name: "Alice", age: 30 })
|
|
411
411
|
* ```
|
|
412
412
|
*/
|
|
413
|
-
|
|
413
|
+
struct: <R extends Record<string, any>>(fields: { [K in keyof R]: Maybe<R[K]>; }) => Maybe<R>;
|
|
414
414
|
/**
|
|
415
415
|
* Swaps the outer `Maybe` and inner `Result` context.
|
|
416
416
|
* `Some(Ok(a))` becomes `Ok(Some(a))`, `Some(Err(e))` becomes `Err(e)`, and `None` becomes `Ok(None)`.
|
|
@@ -422,8 +422,8 @@ declare namespace Maybe {
|
|
|
422
422
|
* Maybe.transposeResult(Maybe.make.none()); // Ok(None)
|
|
423
423
|
* ```
|
|
424
424
|
*/
|
|
425
|
-
|
|
426
|
-
}
|
|
425
|
+
transposeResult: <E, A>(data: Maybe<Result<E, A>>) => Result<E, Maybe<A>>;
|
|
426
|
+
};
|
|
427
427
|
|
|
428
428
|
/**
|
|
429
429
|
* A function that orders two values of type `A`. Returns a negative number when `a` comes before
|
|
@@ -442,7 +442,7 @@ declare namespace Maybe {
|
|
|
442
442
|
* ```
|
|
443
443
|
*/
|
|
444
444
|
type Ordering<A> = (a: A, b: A) => number;
|
|
445
|
-
declare
|
|
445
|
+
declare const Ordering: {
|
|
446
446
|
/**
|
|
447
447
|
* Alphabetical ordering for strings.
|
|
448
448
|
*
|
|
@@ -451,7 +451,7 @@ declare namespace Ordering {
|
|
|
451
451
|
* Ordering.string("apple", "banana"); // negative
|
|
452
452
|
* ```
|
|
453
453
|
*/
|
|
454
|
-
|
|
454
|
+
string: Ordering<string>;
|
|
455
455
|
/**
|
|
456
456
|
* Numeric ordering. Equivalent to `(a, b) => a - b`.
|
|
457
457
|
*
|
|
@@ -460,7 +460,7 @@ declare namespace Ordering {
|
|
|
460
460
|
* pipe([3, 1, 2], Arr.sortWith(Ordering.number)); // [1, 2, 3]
|
|
461
461
|
* ```
|
|
462
462
|
*/
|
|
463
|
-
|
|
463
|
+
number: Ordering<number>;
|
|
464
464
|
/**
|
|
465
465
|
* Ordering for `Date` values by numeric time value.
|
|
466
466
|
*
|
|
@@ -469,7 +469,7 @@ declare namespace Ordering {
|
|
|
469
469
|
* pipe(dates, Arr.sortWith(Ordering.date)); // earliest first
|
|
470
470
|
* ```
|
|
471
471
|
*/
|
|
472
|
-
|
|
472
|
+
date: Ordering<Date>;
|
|
473
473
|
/**
|
|
474
474
|
* Flips the direction of an ordering.
|
|
475
475
|
*
|
|
@@ -478,7 +478,7 @@ declare namespace Ordering {
|
|
|
478
478
|
* pipe([3, 1, 2], Arr.sortWith(Ordering.reverse(Ordering.number))); // [3, 2, 1]
|
|
479
479
|
* ```
|
|
480
480
|
*/
|
|
481
|
-
|
|
481
|
+
reverse: <A>(ord: Ordering<A>) => Ordering<A>;
|
|
482
482
|
/**
|
|
483
483
|
* Chains two orderings: the second is used only when the first returns `0`.
|
|
484
484
|
* Data-last: the first ordering is the data being piped.
|
|
@@ -488,7 +488,7 @@ declare namespace Ordering {
|
|
|
488
488
|
* const byDeptThenSalary = pipe(byDept, Ordering.thenBy(bySalary));
|
|
489
489
|
* ```
|
|
490
490
|
*/
|
|
491
|
-
|
|
491
|
+
thenBy: <A>(ord2: Ordering<A>) => (ord1: Ordering<A>) => Ordering<A>;
|
|
492
492
|
/**
|
|
493
493
|
* Adapts an ordering for type `A` into an ordering for type `B` by extracting a field.
|
|
494
494
|
* Read as "ordering by this field": `pipe(Ordering.number, Ordering.by(p => p.price))`.
|
|
@@ -500,7 +500,7 @@ declare namespace Ordering {
|
|
|
500
500
|
* pipe(products, Arr.sortWith(byPrice));
|
|
501
501
|
* ```
|
|
502
502
|
*/
|
|
503
|
-
|
|
503
|
+
by: <A, B>(f: (b: B) => A) => (ord: Ordering<A>) => Ordering<B>;
|
|
504
504
|
/**
|
|
505
505
|
* Combines a list of orderings into a single composite comparator.
|
|
506
506
|
* Evaluates each ordering in sequence until a non-zero comparison result is found.
|
|
@@ -512,7 +512,7 @@ declare namespace Ordering {
|
|
|
512
512
|
* const sortUsers = Ordering.byFields([byName, byAge]);
|
|
513
513
|
* ```
|
|
514
514
|
*/
|
|
515
|
-
|
|
515
|
+
byFields: <A>(orderings: ReadonlyArray<Ordering<A>>) => Ordering<A>;
|
|
516
516
|
/**
|
|
517
517
|
* Derives a lexicographical tuple ordering from positional `Ordering` comparators.
|
|
518
518
|
*
|
|
@@ -522,8 +522,8 @@ declare namespace Ordering {
|
|
|
522
522
|
* pairOrd(["a", 1], ["a", 2]); // negative
|
|
523
523
|
* ```
|
|
524
524
|
*/
|
|
525
|
-
|
|
526
|
-
}
|
|
525
|
+
tuple: <T extends readonly unknown[]>(...orderings: { [K in keyof T]: Ordering<T[K]>; }) => Ordering<T>;
|
|
526
|
+
};
|
|
527
527
|
|
|
528
528
|
type Ok<A> = WithKind<"Ok"> & WithValue<A>;
|
|
529
529
|
type Err<E> = WithKind<"Err"> & WithError<E>;
|
|
@@ -544,8 +544,8 @@ type Err<E> = WithKind<"Err"> & WithError<E>;
|
|
|
544
544
|
* ```
|
|
545
545
|
*/
|
|
546
546
|
type Result<E, A> = Ok<A> | Err<E>;
|
|
547
|
-
declare
|
|
548
|
-
|
|
547
|
+
declare const Result: {
|
|
548
|
+
make: {
|
|
549
549
|
/**
|
|
550
550
|
* Creates a successful Result with the given value.
|
|
551
551
|
*
|
|
@@ -554,7 +554,7 @@ declare namespace Result {
|
|
|
554
554
|
* Result.make.ok(42); // Ok(42)
|
|
555
555
|
* ```
|
|
556
556
|
*/
|
|
557
|
-
|
|
557
|
+
ok: <A>(value: A) => Ok<A>;
|
|
558
558
|
/**
|
|
559
559
|
* Creates a failed Result with the given error.
|
|
560
560
|
*
|
|
@@ -563,9 +563,9 @@ declare namespace Result {
|
|
|
563
563
|
* Result.make.err("Error message"); // Err("Error message")
|
|
564
564
|
* ```
|
|
565
565
|
*/
|
|
566
|
-
|
|
567
|
-
}
|
|
568
|
-
|
|
566
|
+
err: <E>(e: E) => Err<E>;
|
|
567
|
+
};
|
|
568
|
+
is: {
|
|
569
569
|
/**
|
|
570
570
|
* Type guard that checks if a Result is Ok.
|
|
571
571
|
*
|
|
@@ -577,7 +577,7 @@ declare namespace Result {
|
|
|
577
577
|
* }
|
|
578
578
|
* ```
|
|
579
579
|
*/
|
|
580
|
-
|
|
580
|
+
ok: <E, A>(data: Result<E, A>) => data is Ok<A>;
|
|
581
581
|
/**
|
|
582
582
|
* Type guard that checks if a Result is Err.
|
|
583
583
|
*
|
|
@@ -589,12 +589,8 @@ declare namespace Result {
|
|
|
589
589
|
* }
|
|
590
590
|
* ```
|
|
591
591
|
*/
|
|
592
|
-
|
|
593
|
-
}
|
|
594
|
-
/**
|
|
595
|
-
* Creates a Result from a function that may throw.
|
|
596
|
-
* Catches any errors and transforms them using the onError function.
|
|
597
|
-
*
|
|
592
|
+
err: <E, A>(data: Result<E, A>) => data is Err<E>;
|
|
593
|
+
};
|
|
598
594
|
/**
|
|
599
595
|
* Creates a Result from a synchronous thunk that may throw.
|
|
600
596
|
* Catches any errors and transforms them using the `onError` function.
|
|
@@ -607,7 +603,7 @@ declare namespace Result {
|
|
|
607
603
|
* );
|
|
608
604
|
* ```
|
|
609
605
|
*/
|
|
610
|
-
|
|
606
|
+
tryCatch: <E, A>(f: () => A, options: {
|
|
611
607
|
onError: (e: unknown) => E;
|
|
612
608
|
}) => Result<E, A>;
|
|
613
609
|
/**
|
|
@@ -619,7 +615,7 @@ declare namespace Result {
|
|
|
619
615
|
* pipe(Result.make.err("error"), Result.map(n => n * 2)); // Err("error")
|
|
620
616
|
* ```
|
|
621
617
|
*/
|
|
622
|
-
|
|
618
|
+
map: <E, A, B>(f: (a: A) => B) => (data: Result<E, A>) => Result<E, B>;
|
|
623
619
|
/**
|
|
624
620
|
* Transforms the error value inside a Result.
|
|
625
621
|
*
|
|
@@ -628,7 +624,7 @@ declare namespace Result {
|
|
|
628
624
|
* pipe(Result.make.err("oops"), Result.mapError(e => e.toUpperCase())); // Err("OOPS")
|
|
629
625
|
* ```
|
|
630
626
|
*/
|
|
631
|
-
|
|
627
|
+
mapError: <E, F, A>(f: (e: E) => F) => (data: Result<E, A>) => Result<F, A>;
|
|
632
628
|
/**
|
|
633
629
|
* Chains Result computations. If the first is Ok, passes the value to f.
|
|
634
630
|
* If the first is Err, propagates the error.
|
|
@@ -642,7 +638,7 @@ declare namespace Result {
|
|
|
642
638
|
* pipe(Result.make.ok(-1), Result.chain(validatePositive)); // Err("Must be positive")
|
|
643
639
|
* ```
|
|
644
640
|
*/
|
|
645
|
-
|
|
641
|
+
chain: <E2, A, B>(f: (a: A) => Result<E2, B>) => <E1 = never>(data: Result<E1, A>) => Result<E1 | E2, B>;
|
|
646
642
|
/**
|
|
647
643
|
* Extracts the value from a Result by providing handlers for both cases.
|
|
648
644
|
*
|
|
@@ -657,7 +653,7 @@ declare namespace Result {
|
|
|
657
653
|
* ); // "Value: 5"
|
|
658
654
|
* ```
|
|
659
655
|
*/
|
|
660
|
-
|
|
656
|
+
fold: <E, A, B>(onErr: (e: E) => B, onOk: (a: A) => B) => (data: Result<E, A>) => B;
|
|
661
657
|
/**
|
|
662
658
|
* Pattern matches on a Result, returning the result of the matching case.
|
|
663
659
|
*
|
|
@@ -672,7 +668,7 @@ declare namespace Result {
|
|
|
672
668
|
* );
|
|
673
669
|
* ```
|
|
674
670
|
*/
|
|
675
|
-
|
|
671
|
+
match: <E, A, B>(cases: {
|
|
676
672
|
ok: (a: A) => B;
|
|
677
673
|
err: (e: E) => B;
|
|
678
674
|
}) => (data: Result<E, A>) => B;
|
|
@@ -688,7 +684,7 @@ declare namespace Result {
|
|
|
688
684
|
* pipe(Result.make.err("error"), Result.getOrElse(() => null)); // null — typed as number | null
|
|
689
685
|
* ```
|
|
690
686
|
*/
|
|
691
|
-
|
|
687
|
+
getOrElse: <B>(defaultValue: () => B) => <E, A>(data: Result<E, A>) => A | B;
|
|
692
688
|
/**
|
|
693
689
|
* Executes a side effect on the success value without changing the Result.
|
|
694
690
|
* Useful for logging or debugging.
|
|
@@ -702,7 +698,7 @@ declare namespace Result {
|
|
|
702
698
|
* );
|
|
703
699
|
* ```
|
|
704
700
|
*/
|
|
705
|
-
|
|
701
|
+
tap: <E, A>(f: (a: A) => void) => (data: Result<E, A>) => Result<E, A>;
|
|
706
702
|
/**
|
|
707
703
|
* Executes a side effect on the error value without changing the Result.
|
|
708
704
|
* Useful for logging or reporting errors.
|
|
@@ -716,8 +712,8 @@ declare namespace Result {
|
|
|
716
712
|
* )
|
|
717
713
|
* ```
|
|
718
714
|
*/
|
|
719
|
-
|
|
720
|
-
|
|
715
|
+
tapError: <E, A>(f: (e: E) => void) => (data: Result<E, A>) => Result<E, A>;
|
|
716
|
+
from: {
|
|
721
717
|
/**
|
|
722
718
|
* Creates a Result from a predicate applied to a value.
|
|
723
719
|
* Returns Ok if the predicate passes, Err from onFalse otherwise.
|
|
@@ -729,7 +725,7 @@ declare namespace Result {
|
|
|
729
725
|
* pipe("", Result.from.Predicate(s => s.length > 0, () => "empty string")); // Err("empty string")
|
|
730
726
|
* ```
|
|
731
727
|
*/
|
|
732
|
-
|
|
728
|
+
Predicate: <E, A>(pred: (a: A) => boolean, onFalse: (a: A) => E) => (a: A) => Result<E, A>;
|
|
733
729
|
/**
|
|
734
730
|
* Creates a Result from a nullable value.
|
|
735
731
|
* Returns Ok if the value is not null or undefined, error from onNull otherwise.
|
|
@@ -740,7 +736,7 @@ declare namespace Result {
|
|
|
740
736
|
* pipe(42, Result.from.nullable(() => "is null")); // Ok(42)
|
|
741
737
|
* ```
|
|
742
738
|
*/
|
|
743
|
-
|
|
739
|
+
nullable: <E>(onNull: () => E) => <A>(value: A | null | undefined) => Result<E, A>;
|
|
744
740
|
/**
|
|
745
741
|
* Creates a Result from a Maybe.
|
|
746
742
|
* Some becomes Ok, None becomes error from onNone.
|
|
@@ -751,7 +747,7 @@ declare namespace Result {
|
|
|
751
747
|
* pipe(Maybe.make.some(42), Result.from.Maybe(() => "is none")); // Ok(42)
|
|
752
748
|
* ```
|
|
753
749
|
*/
|
|
754
|
-
|
|
750
|
+
Maybe: <E>(onNone: () => E) => <A>(maybe: Maybe<A>) => Result<E, A>;
|
|
755
751
|
/**
|
|
756
752
|
* Converts a `Validation` to a `Result`, combining accumulated errors using `combineErrors`.
|
|
757
753
|
* `Passed(a)` becomes `Ok(a)`; `Failed(errors)` becomes `Err(combineErrors(errors))`.
|
|
@@ -761,13 +757,13 @@ declare namespace Result {
|
|
|
761
757
|
* Result.from.Validation((errors) => errors.join(", "))(Validation.make.failed("error1")); // Err("error1")
|
|
762
758
|
* ```
|
|
763
759
|
*/
|
|
764
|
-
|
|
765
|
-
}
|
|
760
|
+
Validation: <E1, E2, A>(combineErrors: (errors: NonEmptyArr<E1>) => E2) => (val: Validation<E1, A>) => Result<E2, A>;
|
|
761
|
+
};
|
|
766
762
|
/**
|
|
767
763
|
* Recovers from an error by providing a fallback Result.
|
|
768
764
|
* The fallback can produce a different success type, widening the result to `Result<E, A | B>`.
|
|
769
765
|
*/
|
|
770
|
-
|
|
766
|
+
recover: <E, B>(fallback: (e: E) => Result<E, B>) => <A>(data: Result<E, A>) => Result<E, A | B>;
|
|
771
767
|
/**
|
|
772
768
|
* Recovers from an error unless the predicate `isBlocked` returns true for that error.
|
|
773
769
|
* The fallback can produce a different success type, widening the result to `Result<E, A | B>`.
|
|
@@ -780,8 +776,8 @@ declare namespace Result {
|
|
|
780
776
|
* ); // Ok(0)
|
|
781
777
|
* ```
|
|
782
778
|
*/
|
|
783
|
-
|
|
784
|
-
|
|
779
|
+
recoverUnless: <E, B>(isBlocked: (e: E) => boolean, fallback: () => Result<E, B>) => <A>(data: Result<E, A>) => Result<E, A | B>;
|
|
780
|
+
to: {
|
|
785
781
|
/**
|
|
786
782
|
* Converts a Result to a Maybe.
|
|
787
783
|
* Ok becomes Some, Err becomes None (the error is discarded).
|
|
@@ -792,7 +788,7 @@ declare namespace Result {
|
|
|
792
788
|
* Result.to.Maybe(Result.make.err("oops")); // None
|
|
793
789
|
* ```
|
|
794
790
|
*/
|
|
795
|
-
|
|
791
|
+
Maybe: <E, A>(data: Result<E, A>) => Maybe<A>;
|
|
796
792
|
/**
|
|
797
793
|
* Converts a `Result` to a `Validation`. `Ok(a)` becomes `Passed(a)`; `Err(e)` becomes `Failed([e])`.
|
|
798
794
|
*
|
|
@@ -802,8 +798,8 @@ declare namespace Result {
|
|
|
802
798
|
* Result.to.Validation(Result.make.err("bad")); // Failed(["bad"])
|
|
803
799
|
* ```
|
|
804
800
|
*/
|
|
805
|
-
|
|
806
|
-
}
|
|
801
|
+
Validation: <E, A>(data: Result<E, A>) => Validation<E, A>;
|
|
802
|
+
};
|
|
807
803
|
/**
|
|
808
804
|
* Swaps the outer `Result` and inner `Maybe` context.
|
|
809
805
|
* `Ok(Some(a))` becomes `Some(Ok(a))`, `Ok(None)` becomes `None`, and `Err(e)` becomes `Some(Err(e))`.
|
|
@@ -815,7 +811,7 @@ declare namespace Result {
|
|
|
815
811
|
* Result.transposeMaybe(Result.make.err("error")); // Some(Err("error"))
|
|
816
812
|
* ```
|
|
817
813
|
*/
|
|
818
|
-
|
|
814
|
+
transposeMaybe: <E, A>(data: Result<E, Maybe<A>>) => Maybe<Result<E, A>>;
|
|
819
815
|
/**
|
|
820
816
|
* Applies a function wrapped in a Result to a value wrapped in a Result.
|
|
821
817
|
*
|
|
@@ -829,7 +825,7 @@ declare namespace Result {
|
|
|
829
825
|
* ); // Ok(8)
|
|
830
826
|
* ```
|
|
831
827
|
*/
|
|
832
|
-
|
|
828
|
+
ap: <E, A>(arg: Result<E, A>) => <B>(data: Result<E, (a: A) => B>) => Result<E, B>;
|
|
833
829
|
/**
|
|
834
830
|
* Converts a Result value into an object containing a single property.
|
|
835
831
|
* Initiates the pipeline accumulator record.
|
|
@@ -839,7 +835,7 @@ declare namespace Result {
|
|
|
839
835
|
* pipe(Result.make.ok(42), Result.bindTo("value")); // Ok({ value: 42 })
|
|
840
836
|
* ```
|
|
841
837
|
*/
|
|
842
|
-
|
|
838
|
+
bindTo: <K extends string>(key: K) => <E, A>(data: Result<E, A>) => Result<E, { [P in K]: A; }>;
|
|
843
839
|
/**
|
|
844
840
|
* Evaluates a new Result using the current accumulator and attaches the output to a new key.
|
|
845
841
|
*
|
|
@@ -851,7 +847,7 @@ declare namespace Result {
|
|
|
851
847
|
* ); // Ok({ a: 1, b: 2 })
|
|
852
848
|
* ```
|
|
853
849
|
*/
|
|
854
|
-
|
|
850
|
+
bind: <K extends string, E, A, B>(key: K, f: (a: A) => Result<E, B>) => (data: Result<E, A>) => Result<E, A & { [P in K]: B; }>;
|
|
855
851
|
/**
|
|
856
852
|
* Combines a record of Results into a single Result of a record.
|
|
857
853
|
* Evaluates fields in key order and short-circuits on the first failure.
|
|
@@ -864,7 +860,7 @@ declare namespace Result {
|
|
|
864
860
|
* }); // Ok({ name: "Alice", age: 30 })
|
|
865
861
|
* ```
|
|
866
862
|
*/
|
|
867
|
-
|
|
863
|
+
struct: <E, R extends Record<string, any>>(fields: { [K in keyof R]: Result<E, R[K]>; }) => Result<E, R>;
|
|
868
864
|
/**
|
|
869
865
|
* Narrows an `Ok` value with a predicate, converting to `Err(onFail(a))` if the predicate returns false.
|
|
870
866
|
*
|
|
@@ -876,7 +872,7 @@ declare namespace Result {
|
|
|
876
872
|
* ); // Err("Age 15 is below 18")
|
|
877
873
|
* ```
|
|
878
874
|
*/
|
|
879
|
-
|
|
875
|
+
ensure: <A, E2>(predicate: (a: A) => boolean, onFail: (a: A) => E2) => <E1 = never>(data: Result<E1, A>) => Result<E1 | E2, A>;
|
|
880
876
|
/**
|
|
881
877
|
* Transforms both branches of a Result simultaneously.
|
|
882
878
|
* Applies `onErr` to `Err` values and `onOk` to `Ok` values.
|
|
@@ -892,1562 +888,861 @@ declare namespace Result {
|
|
|
892
888
|
* ); // Ok(10)
|
|
893
889
|
* ```
|
|
894
890
|
*/
|
|
895
|
-
|
|
896
|
-
}
|
|
891
|
+
bimap: <E1, E2, A, B>(onErr: (e: E1) => E2, onOk: (a: A) => B) => (data: Result<E1, A>) => Result<E2, B>;
|
|
892
|
+
};
|
|
897
893
|
|
|
894
|
+
type Passed<A> = WithKind<"Passed"> & WithValue<A>;
|
|
895
|
+
type Failed<E> = WithKind<"Failed"> & WithErrors<E>;
|
|
896
|
+
declare function toResult<E1, E2, A>(combineErrors: (errors: NonEmptyArr<E1>) => E2): (val: Validation<E1, A>) => Result<E2, A>;
|
|
897
|
+
declare function toResult<E, A>(data: Validation<E, A>): Result<NonEmptyArr<E>, A>;
|
|
898
898
|
/**
|
|
899
|
-
*
|
|
900
|
-
*
|
|
899
|
+
* Validation represents a value that is either passed with a success value,
|
|
900
|
+
* or failed with accumulated errors.
|
|
901
|
+
* Unlike Result, Validation can accumulate multiple errors instead of short-circuiting.
|
|
901
902
|
*
|
|
902
|
-
* Use
|
|
903
|
+
* Use Validation when you need to collect all errors (e.g., form validation).
|
|
904
|
+
* Use Result when you want to fail fast on the first error.
|
|
903
905
|
*
|
|
904
906
|
* @example
|
|
905
907
|
* ```ts
|
|
906
|
-
* const
|
|
907
|
-
*
|
|
908
|
-
*
|
|
909
|
-
*
|
|
908
|
+
* const validateName = (name: string): Validation<string, string> =>
|
|
909
|
+
* name.length > 0 ? Validation.make.passed(name) : Validation.make.failed("Name is required");
|
|
910
|
+
*
|
|
911
|
+
* const validateAge = (age: number): Validation<string, number> =>
|
|
912
|
+
* age >= 0 ? Validation.make.passed(age) : Validation.make.failed("Age must be positive");
|
|
913
|
+
*
|
|
914
|
+
* // Accumulates all errors using ap
|
|
915
|
+
* pipe(
|
|
916
|
+
* Validation.make.passed((name: string) => (age: number) => ({ name, age })),
|
|
917
|
+
* Validation.ap(validateName("")),
|
|
918
|
+
* Validation.ap(validateAge(-1))
|
|
919
|
+
* );
|
|
920
|
+
* // Failed(["Name is required", "Age must be positive"])
|
|
910
921
|
* ```
|
|
911
922
|
*/
|
|
912
|
-
type
|
|
913
|
-
declare
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
923
|
+
type Validation<E, A> = Passed<A> | Failed<E>;
|
|
924
|
+
declare const Validation: {
|
|
925
|
+
make: {
|
|
926
|
+
/**
|
|
927
|
+
* Wraps a value in a passed Validation.
|
|
928
|
+
*
|
|
929
|
+
* @example
|
|
930
|
+
* ```ts
|
|
931
|
+
* Validation.make.passed(42); // Passed(42)
|
|
932
|
+
* ```
|
|
933
|
+
*/
|
|
934
|
+
passed: <E, A>(value: A) => Validation<E, A>;
|
|
935
|
+
/**
|
|
936
|
+
* Creates a failed Validation from a single error.
|
|
937
|
+
*
|
|
938
|
+
* @example
|
|
939
|
+
* ```ts
|
|
940
|
+
* Validation.make.failed("Invalid input");
|
|
941
|
+
* ```
|
|
942
|
+
*/
|
|
943
|
+
failed: <E>(error: E) => Failed<E>;
|
|
944
|
+
/**
|
|
945
|
+
* Creates a failed Validation from multiple errors.
|
|
946
|
+
*
|
|
947
|
+
* @example
|
|
948
|
+
* ```ts
|
|
949
|
+
* Validation.make.failedAll(["Invalid input"]);
|
|
950
|
+
* ```
|
|
951
|
+
*/
|
|
952
|
+
failedAll: <E>(errors: NonEmptyArr<E>) => Failed<E>;
|
|
953
|
+
};
|
|
954
|
+
is: {
|
|
924
955
|
/**
|
|
925
|
-
*
|
|
956
|
+
* Type guard that checks if a Validation is passed.
|
|
926
957
|
*
|
|
927
958
|
* @example
|
|
928
959
|
* ```ts
|
|
929
|
-
* const
|
|
930
|
-
*
|
|
960
|
+
* const v = Validation.make.passed(42);
|
|
961
|
+
* if (Validation.is.passed(v)) {
|
|
962
|
+
* console.log(v.value); // 42
|
|
963
|
+
* }
|
|
931
964
|
* ```
|
|
932
965
|
*/
|
|
933
|
-
|
|
966
|
+
passed: <E, A>(data: Validation<E, A>) => data is Passed<A>;
|
|
934
967
|
/**
|
|
935
|
-
*
|
|
968
|
+
* Type guard that checks if a Validation is failed.
|
|
936
969
|
*
|
|
937
970
|
* @example
|
|
938
971
|
* ```ts
|
|
939
|
-
* const
|
|
940
|
-
*
|
|
972
|
+
* const v = Validation.make.failed("invalid");
|
|
973
|
+
* if (Validation.is.failed(v)) {
|
|
974
|
+
* console.log(v.errors); // ["invalid"]
|
|
975
|
+
* }
|
|
941
976
|
* ```
|
|
942
977
|
*/
|
|
943
|
-
|
|
944
|
-
}
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
978
|
+
failed: <E, A>(data: Validation<E, A>) => data is Failed<E>;
|
|
979
|
+
};
|
|
980
|
+
/**
|
|
981
|
+
* Creates a Validation from a synchronous thunk that may throw.
|
|
982
|
+
* Catches any errors and transforms them using the `onError` function into a Failed validation.
|
|
983
|
+
*
|
|
984
|
+
* @example
|
|
985
|
+
* ```ts
|
|
986
|
+
* const result = Validation.tryCatch(
|
|
987
|
+
* () => JSON.parse(rawString),
|
|
988
|
+
* { onError: (e) => `Parse error: ${e}` }
|
|
989
|
+
* );
|
|
990
|
+
* ```
|
|
991
|
+
*/
|
|
992
|
+
tryCatch: <E, A>(f: () => A, options: {
|
|
993
|
+
onError: (e: unknown) => E;
|
|
994
|
+
}) => Validation<E, A>;
|
|
995
|
+
from: {
|
|
948
996
|
/**
|
|
949
|
-
*
|
|
997
|
+
* Creates a Validation from a predicate applied to a value.
|
|
998
|
+
* Returns Passed if the predicate passes, Failed from `onFalse` otherwise.
|
|
950
999
|
*
|
|
951
1000
|
* @example
|
|
952
1001
|
* ```ts
|
|
953
|
-
*
|
|
1002
|
+
* const validateName = Validation.from.Predicate(
|
|
1003
|
+
* (s: string) => s.length > 0,
|
|
1004
|
+
* () => "Name is required"
|
|
1005
|
+
* );
|
|
1006
|
+
*
|
|
1007
|
+
* validateName("Alice"); // Passed("Alice")
|
|
1008
|
+
* validateName(""); // Failed(["Name is required"])
|
|
954
1009
|
* ```
|
|
955
1010
|
*/
|
|
956
|
-
|
|
1011
|
+
Predicate: <E, A>(pred: (a: A) => boolean, onFalse: (a: A) => E) => (a: A) => Validation<E, A>;
|
|
957
1012
|
/**
|
|
958
|
-
* Creates a
|
|
959
|
-
*
|
|
1013
|
+
* Creates a Validation from a nullable value.
|
|
1014
|
+
* If the value is null or undefined, returns Failed with the error from onNull.
|
|
1015
|
+
* Otherwise, returns Passed.
|
|
960
1016
|
*
|
|
961
1017
|
* @example
|
|
962
1018
|
* ```ts
|
|
963
|
-
*
|
|
964
|
-
*
|
|
1019
|
+
* pipe(null, Validation.from.nullable(() => "is null")); // Failed(["is null"])
|
|
1020
|
+
* pipe(42, Validation.from.nullable(() => "is null")); // Passed(42)
|
|
965
1021
|
* ```
|
|
966
1022
|
*/
|
|
967
|
-
|
|
1023
|
+
nullable: <E>(onNull: () => E) => <A>(value: A | null | undefined) => Validation<E, A>;
|
|
968
1024
|
/**
|
|
969
|
-
* Creates a
|
|
970
|
-
*
|
|
1025
|
+
* Creates a Validation from a Maybe.
|
|
1026
|
+
* If the Maybe is None, returns Failed with the error from onNone.
|
|
1027
|
+
* Otherwise, returns Passed.
|
|
971
1028
|
*
|
|
972
1029
|
* @example
|
|
973
1030
|
* ```ts
|
|
974
|
-
*
|
|
975
|
-
*
|
|
1031
|
+
* pipe(Maybe.make.none(), Validation.from.Maybe(() => "is none")); // Failed(["is none"])
|
|
1032
|
+
* pipe(Maybe.make.some(42), Validation.from.Maybe(() => "is none")); // Passed(42)
|
|
976
1033
|
* ```
|
|
977
1034
|
*/
|
|
978
|
-
|
|
1035
|
+
Maybe: <E>(onNone: () => E) => <A>(maybe: Maybe<A>) => Validation<E, A>;
|
|
979
1036
|
/**
|
|
980
|
-
*
|
|
1037
|
+
* Converts a `Result` to a `Validation`. `Ok` becomes `Passed`; `Err(e)` becomes `Failed([e])`.
|
|
1038
|
+
*
|
|
1039
|
+
* Useful when bridging from error-short-circuiting `Result` pipelines into
|
|
1040
|
+
* error-accumulating `Validation` pipelines.
|
|
981
1041
|
*
|
|
982
1042
|
* @example
|
|
983
1043
|
* ```ts
|
|
984
|
-
*
|
|
1044
|
+
* Validation.from.Result(Result.make.ok(42)); // Passed(42)
|
|
1045
|
+
* Validation.from.Result(Result.make.err("bad")); // Failed(["bad"])
|
|
985
1046
|
* ```
|
|
986
1047
|
*/
|
|
987
|
-
|
|
988
|
-
}
|
|
1048
|
+
Result: <E, A>(data: Result<E, A>) => Validation<E, A>;
|
|
1049
|
+
};
|
|
989
1050
|
/**
|
|
990
|
-
*
|
|
991
|
-
* Returns Some if the promise resolves, None if it rejects.
|
|
992
|
-
* The factory optionally receives an `AbortSignal` forwarded from the call site.
|
|
1051
|
+
* Transforms the success value inside a Validation.
|
|
993
1052
|
*
|
|
994
1053
|
* @example
|
|
995
1054
|
* ```ts
|
|
996
|
-
*
|
|
997
|
-
*
|
|
998
|
-
* );
|
|
1055
|
+
* pipe(Validation.make.passed(5), Validation.map(n => n * 2)); // Passed(10)
|
|
1056
|
+
* pipe(Validation.make.failed("oops"), Validation.map(n => n * 2)); // Failed(["oops"])
|
|
999
1057
|
* ```
|
|
1000
1058
|
*/
|
|
1001
|
-
|
|
1059
|
+
map: <A, B>(f: (a: A) => B) => <E>(data: Validation<E, A>) => Validation<E, B>;
|
|
1002
1060
|
/**
|
|
1003
|
-
* Transforms the
|
|
1061
|
+
* Transforms the error list inside a Validation.
|
|
1062
|
+
*
|
|
1063
|
+
* @example
|
|
1064
|
+
* ```ts
|
|
1065
|
+
* pipe(Validation.make.failed("oops"), Validation.mapError(e => e.toUpperCase())); // Failed(["OOPS"])
|
|
1066
|
+
* ```
|
|
1004
1067
|
*/
|
|
1005
|
-
|
|
1068
|
+
mapError: <E, F, A>(f: (e: E) => F) => (data: Validation<E, A>) => Validation<F, A>;
|
|
1006
1069
|
/**
|
|
1007
|
-
*
|
|
1008
|
-
*
|
|
1070
|
+
* Applies a function wrapped in a Validation to a value wrapped in a Validation.
|
|
1071
|
+
* Accumulates errors from both sides.
|
|
1009
1072
|
*
|
|
1010
1073
|
* @example
|
|
1011
1074
|
* ```ts
|
|
1075
|
+
* const add = (a: number) => (b: number) => a + b;
|
|
1076
|
+
* pipe(
|
|
1077
|
+
* Validation.make.passed(add),
|
|
1078
|
+
* Validation.ap(Validation.make.passed(5)),
|
|
1079
|
+
* Validation.ap(Validation.make.passed(3))
|
|
1080
|
+
* ); // Passed(8)
|
|
1081
|
+
*
|
|
1012
1082
|
* pipe(
|
|
1013
|
-
*
|
|
1014
|
-
*
|
|
1015
|
-
* )
|
|
1083
|
+
* Validation.make.passed(add),
|
|
1084
|
+
* Validation.ap(Validation.make.failed<string>("bad a")),
|
|
1085
|
+
* Validation.ap(Validation.make.failed<string>("bad b"))
|
|
1086
|
+
* ); // Failed(["bad a", "bad b"])
|
|
1016
1087
|
* ```
|
|
1017
1088
|
*/
|
|
1018
|
-
|
|
1089
|
+
ap: <E, A>(arg: Validation<E, A>) => <B>(data: Validation<E, (a: A) => B>) => Validation<E, B>;
|
|
1019
1090
|
/**
|
|
1020
|
-
* Applies a function wrapped in a
|
|
1021
|
-
*
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
*
|
|
1091
|
+
* Applies a function wrapped in a Validation to a value wrapped in a Validation,
|
|
1092
|
+
* using a custom error concatenator function when both sides fail.
|
|
1093
|
+
*
|
|
1094
|
+
* @example
|
|
1095
|
+
* ```ts
|
|
1096
|
+
* const concat = (e1: NonEmptyArr<string>, e2: NonEmptyArr<string>): NonEmptyArr<string> =>
|
|
1097
|
+
* [...e1, ...e2];
|
|
1098
|
+
* pipe(fnVal, Validation.apCustom(concat)(argVal));
|
|
1099
|
+
* ```
|
|
1026
1100
|
*/
|
|
1027
|
-
|
|
1101
|
+
apCustom: <E1, E2, E3>(concat: (e1: NonEmptyArr<E1>, e2: NonEmptyArr<E2>) => NonEmptyArr<E3>) => <A>(arg: Validation<E2, A>) => <B>(data: Validation<E1, (a: A) => B>) => Validation<E3, B>;
|
|
1028
1102
|
/**
|
|
1029
|
-
*
|
|
1103
|
+
* Extracts the value from a Validation by providing handlers for both cases.
|
|
1030
1104
|
*
|
|
1031
1105
|
* @example
|
|
1032
1106
|
* ```ts
|
|
1033
1107
|
* pipe(
|
|
1034
|
-
*
|
|
1035
|
-
*
|
|
1036
|
-
*
|
|
1037
|
-
*
|
|
1038
|
-
*
|
|
1039
|
-
* )
|
|
1108
|
+
* Validation.make.passed(42),
|
|
1109
|
+
* Validation.fold(
|
|
1110
|
+
* errors => `Errors: ${errors.join(", ")}`,
|
|
1111
|
+
* value => `Value: ${value}`
|
|
1112
|
+
* )
|
|
1113
|
+
* );
|
|
1040
1114
|
* ```
|
|
1041
1115
|
*/
|
|
1042
|
-
|
|
1043
|
-
none: () => B;
|
|
1044
|
-
some: (a: A) => B;
|
|
1045
|
-
}) => (data: TaskMaybe<A>) => Task<B>;
|
|
1046
|
-
/**
|
|
1047
|
-
* Returns the value or a default if the Task.Maybe resolves to None.
|
|
1048
|
-
* The default can be a different type, widening the result to `Task<A | B>`.
|
|
1049
|
-
*/
|
|
1050
|
-
const getOrElse: <B>(defaultValue: () => B) => <A>(data: TaskMaybe<A>) => Task<A | B>;
|
|
1051
|
-
/**
|
|
1052
|
-
* Executes a side effect on the value without changing the Task.Maybe.
|
|
1053
|
-
* Useful for logging or debugging.
|
|
1054
|
-
*/
|
|
1055
|
-
const tap: <A>(f: (a: A) => void) => (data: TaskMaybe<A>) => TaskMaybe<A>;
|
|
1056
|
-
/**
|
|
1057
|
-
* Filters the value inside a Task.Maybe. Returns None if the predicate fails.
|
|
1058
|
-
*/
|
|
1059
|
-
const filter: <A>(predicate: (a: A) => boolean) => (data: TaskMaybe<A>) => TaskMaybe<A>;
|
|
1060
|
-
namespace to {
|
|
1061
|
-
/**
|
|
1062
|
-
* Converts a Task.Maybe to a Task.Result, using onNone to produce the error value.
|
|
1063
|
-
*
|
|
1064
|
-
* @example
|
|
1065
|
-
* ```ts
|
|
1066
|
-
* pipe(
|
|
1067
|
-
* findUser("123"),
|
|
1068
|
-
* Task.Maybe.to.Result(() => "User not found")
|
|
1069
|
-
* );
|
|
1070
|
-
* ```
|
|
1071
|
-
*/
|
|
1072
|
-
const Result: <E>(onNone: () => E) => <A>(data: TaskMaybe<A>) => Task.Result<E, A>;
|
|
1073
|
-
}
|
|
1116
|
+
fold: <E, A, B>(onFailed: (errors: NonEmptyArr<E>) => B, onPassed: (a: A) => B) => (data: Validation<E, A>) => B;
|
|
1074
1117
|
/**
|
|
1075
|
-
*
|
|
1118
|
+
* Pattern matches on a Validation, returning the result of the matching case.
|
|
1076
1119
|
*
|
|
1077
1120
|
* @example
|
|
1078
1121
|
* ```ts
|
|
1079
|
-
* pipe(
|
|
1122
|
+
* pipe(
|
|
1123
|
+
* validation,
|
|
1124
|
+
* Validation.match({
|
|
1125
|
+
* passed: value => `Got ${value}`,
|
|
1126
|
+
* failed: errors => `Failed: ${errors.join(", ")}`
|
|
1127
|
+
* })
|
|
1128
|
+
* );
|
|
1080
1129
|
* ```
|
|
1081
1130
|
*/
|
|
1082
|
-
|
|
1131
|
+
match: <E, A, B>(cases: {
|
|
1132
|
+
passed: (a: A) => B;
|
|
1133
|
+
failed: (errors: NonEmptyArr<E>) => B;
|
|
1134
|
+
}) => (data: Validation<E, A>) => B;
|
|
1083
1135
|
/**
|
|
1084
|
-
*
|
|
1136
|
+
* Returns the success value or a default value if the Validation is failed.
|
|
1137
|
+
* The default can be a different type, widening the result to `A | B`.
|
|
1085
1138
|
*
|
|
1086
1139
|
* @example
|
|
1087
1140
|
* ```ts
|
|
1088
|
-
* pipe(
|
|
1089
|
-
*
|
|
1090
|
-
*
|
|
1091
|
-
* ); // Task.Maybe({ a: 1, b: 2 })
|
|
1141
|
+
* pipe(Validation.make.passed(5), Validation.getOrElse(() => 0)); // 5
|
|
1142
|
+
* pipe(Validation.make.failed("oops"), Validation.getOrElse(() => 0)); // 0
|
|
1143
|
+
* pipe(Validation.make.failed("oops"), Validation.getOrElse(() => null)); // null — typed as number | null
|
|
1092
1144
|
* ```
|
|
1093
1145
|
*/
|
|
1094
|
-
|
|
1146
|
+
getOrElse: <B>(defaultValue: () => B) => <E, A>(data: Validation<E, A>) => A | B;
|
|
1095
1147
|
/**
|
|
1096
|
-
*
|
|
1148
|
+
* Executes a side effect on the success value without changing the Validation.
|
|
1097
1149
|
*
|
|
1098
1150
|
* @example
|
|
1099
1151
|
* ```ts
|
|
1100
1152
|
* pipe(
|
|
1101
|
-
*
|
|
1102
|
-
*
|
|
1103
|
-
*
|
|
1153
|
+
* Validation.make.passed(5),
|
|
1154
|
+
* Validation.tap(n => console.log("Value:", n)),
|
|
1155
|
+
* Validation.map(n => n * 2)
|
|
1156
|
+
* );
|
|
1104
1157
|
* ```
|
|
1105
1158
|
*/
|
|
1106
|
-
|
|
1159
|
+
tap: <E, A>(f: (a: A) => void) => (data: Validation<E, A>) => Validation<E, A>;
|
|
1107
1160
|
/**
|
|
1108
|
-
*
|
|
1109
|
-
*
|
|
1161
|
+
* Executes a side effect on the accumulated errors without changing the Validation.
|
|
1162
|
+
* Useful for logging or reporting validation failures.
|
|
1110
1163
|
*
|
|
1111
1164
|
* @example
|
|
1112
1165
|
* ```ts
|
|
1113
|
-
*
|
|
1114
|
-
*
|
|
1115
|
-
*
|
|
1116
|
-
*
|
|
1166
|
+
* pipe(
|
|
1167
|
+
* Validation.make.failed("Name required"),
|
|
1168
|
+
* Validation.tapError(errors => console.error("validation failed:", errors)),
|
|
1169
|
+
* Validation.map(toUser)
|
|
1170
|
+
* );
|
|
1117
1171
|
* ```
|
|
1118
1172
|
*/
|
|
1119
|
-
|
|
1173
|
+
tapError: <E, A>(f: (errors: NonEmptyArr<E>) => void) => (data: Validation<E, A>) => Validation<E, A>;
|
|
1174
|
+
/**
|
|
1175
|
+
* Recovers from a Failed state by providing a fallback Validation.
|
|
1176
|
+
* The fallback receives the accumulated error list so callers can inspect which errors occurred.
|
|
1177
|
+
* The fallback can produce a different success type, widening the result to `Validation<E, A | B>`.
|
|
1178
|
+
*/
|
|
1179
|
+
recover: <E, B>(fallback: (errors: NonEmptyArr<E>) => Validation<E, B>) => <A>(data: Validation<E, A>) => Validation<E, A | B>;
|
|
1120
1180
|
/**
|
|
1121
|
-
*
|
|
1122
|
-
*
|
|
1181
|
+
* Recovers from a Failed state unless `isBlocked` returns true for any of the accumulated errors.
|
|
1182
|
+
* The fallback can produce a different success type, widening the result to `Validation<E, A | B>`.
|
|
1123
1183
|
*
|
|
1124
1184
|
* @example
|
|
1125
1185
|
* ```ts
|
|
1126
|
-
*
|
|
1186
|
+
* pipe(
|
|
1187
|
+
* Validation.make.failed("field-error"),
|
|
1188
|
+
* Validation.recoverUnless(e => e === "fatal", () => Validation.make.passed(0))
|
|
1189
|
+
* ); // Passed(0)
|
|
1127
1190
|
* ```
|
|
1128
1191
|
*/
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
/**
|
|
1133
|
-
* A Task that can fail with an error of type E or succeed with a value of type A.
|
|
1134
|
-
* Combines async operations with typed error handling.
|
|
1135
|
-
*
|
|
1136
|
-
* @example
|
|
1137
|
-
* ```ts
|
|
1138
|
-
* const fetchUser = (id: string): Task.Result<Error, User> =>
|
|
1139
|
-
* Task.Result.tryCatch(
|
|
1140
|
-
* (signal) => fetch(`/users/${id}`, { signal }).then(r => r.json()),
|
|
1141
|
-
* { onError: (e) => new Error(`Failed to fetch user: ${e}`) }
|
|
1142
|
-
* );
|
|
1143
|
-
* ```
|
|
1144
|
-
*/
|
|
1145
|
-
type TaskResult<E, A> = Task<Result<E, A>>;
|
|
1146
|
-
declare namespace TaskResult {
|
|
1147
|
-
namespace make {
|
|
1148
|
-
/**
|
|
1149
|
-
* Wraps a value in a successful Task.Result.
|
|
1150
|
-
*
|
|
1151
|
-
* @example
|
|
1152
|
-
* ```ts
|
|
1153
|
-
* const task = Task.Result.make.ok(42);
|
|
1154
|
-
* const res = await task(); // Ok(42)
|
|
1155
|
-
* ```
|
|
1156
|
-
*/
|
|
1157
|
-
const ok: <E = never, A = unknown>(value: A) => TaskResult<E, A>;
|
|
1158
|
-
/**
|
|
1159
|
-
* Creates a failed Task.Result with the given error.
|
|
1160
|
-
*
|
|
1161
|
-
* @example
|
|
1162
|
-
* ```ts
|
|
1163
|
-
* const task = Task.Result.make.err("failed");
|
|
1164
|
-
* const res = await task(); // Err("failed")
|
|
1165
|
-
* ```
|
|
1166
|
-
*/
|
|
1167
|
-
const err: <E, A = never>(error: E) => TaskResult<E, A>;
|
|
1168
|
-
}
|
|
1169
|
-
const ok: <E = never, A = unknown>(value: A) => TaskResult<E, A>;
|
|
1170
|
-
const err: <E, A = never>(error: E) => TaskResult<E, A>;
|
|
1171
|
-
namespace from {
|
|
1172
|
-
/**
|
|
1173
|
-
* Creates a Task.Result from a nullable value.
|
|
1174
|
-
* Returns Ok if the value is not null or undefined, err from onNull otherwise.
|
|
1175
|
-
*
|
|
1176
|
-
* @example
|
|
1177
|
-
* ```ts
|
|
1178
|
-
* Task.Result.from.nullable(() => "missing")(42); // resolves to Ok(42)
|
|
1179
|
-
* Task.Result.from.nullable(() => "missing")(null); // resolves to Err("missing")
|
|
1180
|
-
* ```
|
|
1181
|
-
*/
|
|
1182
|
-
const nullable: <E>(onNull: () => E) => <A>(value: A | null | undefined) => TaskResult<E, A>;
|
|
1192
|
+
recoverUnless: <E, B>(isBlocked: (e: E) => boolean, fallback: () => Validation<E, B>) => <A>(data: Validation<E, A>) => Validation<E, A | B>;
|
|
1193
|
+
to: {
|
|
1183
1194
|
/**
|
|
1184
|
-
*
|
|
1185
|
-
*
|
|
1195
|
+
* Converts a Validation to a Result.
|
|
1196
|
+
* Passed becomes Ok.
|
|
1197
|
+
* Direct call converts Failed to Err with accumulated error list `NonEmptyArr<E>`.
|
|
1198
|
+
* Curried call converts Failed to Err with combined error `E2` via `combineErrors`.
|
|
1186
1199
|
*
|
|
1187
1200
|
* @example
|
|
1188
1201
|
* ```ts
|
|
1189
|
-
*
|
|
1190
|
-
*
|
|
1202
|
+
* Validation.to.Result(Validation.make.passed(42)); // Ok(42)
|
|
1203
|
+
* Validation.to.Result(Validation.make.failed("oops")); // Err(["oops"])
|
|
1204
|
+
* pipe(Validation.make.failed("oops"), Validation.to.Result(errors => errors.join(", "))); // Err("oops")
|
|
1191
1205
|
* ```
|
|
1192
1206
|
*/
|
|
1193
|
-
|
|
1207
|
+
Result: typeof toResult;
|
|
1194
1208
|
/**
|
|
1195
|
-
*
|
|
1209
|
+
* Converts a Validation to a Maybe. `Passed` becomes `Some`; `Failed` becomes `None`
|
|
1210
|
+
* (errors are discarded).
|
|
1196
1211
|
*
|
|
1197
1212
|
* @example
|
|
1198
1213
|
* ```ts
|
|
1199
|
-
*
|
|
1214
|
+
* Validation.to.Maybe(Validation.make.passed(42)); // Some(42)
|
|
1215
|
+
* Validation.to.Maybe(Validation.make.failed("bad")); // None
|
|
1200
1216
|
* ```
|
|
1201
1217
|
*/
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
*
|
|
1205
|
-
* @example
|
|
1206
|
-
* ```ts
|
|
1207
|
-
* Task.Result.from.Result(Result.make.ok(42)); // resolves to Ok(42)
|
|
1208
|
-
* ```
|
|
1209
|
-
*/
|
|
1210
|
-
const Result: <E, A>(result: Result<E, A>) => TaskResult<E, A>;
|
|
1211
|
-
}
|
|
1212
|
-
namespace to {
|
|
1213
|
-
/**
|
|
1214
|
-
* Converts a Task.Result to a Task.Maybe, dropping the error value on Err.
|
|
1215
|
-
*
|
|
1216
|
-
* @example
|
|
1217
|
-
* ```ts
|
|
1218
|
-
* const taskResult = Task.Result.ok(42);
|
|
1219
|
-
* const taskMaybe = pipe(taskResult, Task.Result.to.Maybe);
|
|
1220
|
-
* ```
|
|
1221
|
-
*/
|
|
1222
|
-
const Maybe: <E, A>(data: TaskResult<E, A>) => TaskMaybe<A>;
|
|
1223
|
-
}
|
|
1224
|
-
/**
|
|
1225
|
-
* Creates a Task.Result from a Promise-returning thunk that may throw or reject.
|
|
1226
|
-
* Catches any errors and transforms them using the `onError` function into an `Err`.
|
|
1227
|
-
* The thunk optionally receives an `AbortSignal` forwarded from the call site.
|
|
1228
|
-
*
|
|
1229
|
-
* @example
|
|
1230
|
-
* ```ts
|
|
1231
|
-
* const loadUser = Task.Result.tryCatch(
|
|
1232
|
-
* (signal) => userStore.get("u_123", { signal }),
|
|
1233
|
-
* { onError: (e) => new DbError(e) }
|
|
1234
|
-
* );
|
|
1235
|
-
* ```
|
|
1236
|
-
*/
|
|
1237
|
-
const tryCatch: <E, A>(f: (signal?: AbortSignal) => Thenable<A>, options: {
|
|
1238
|
-
onError: (error: unknown) => E;
|
|
1239
|
-
}) => TaskResult<E, A>;
|
|
1240
|
-
/**
|
|
1241
|
-
* Transforms the success value inside a Task.Result.
|
|
1242
|
-
*/
|
|
1243
|
-
const map: <E, A, B>(f: (a: A) => B) => (data: TaskResult<E, A>) => TaskResult<E, B>;
|
|
1244
|
-
/**
|
|
1245
|
-
* Transforms the error value inside a Task.Result.
|
|
1246
|
-
*/
|
|
1247
|
-
const mapError: <E, F, A>(f: (e: E) => F) => (data: TaskResult<E, A>) => TaskResult<F, A>;
|
|
1248
|
-
/**
|
|
1249
|
-
* Chains Task.Result computations. If the first succeeds, passes the value to f.
|
|
1250
|
-
* If the first fails, propagates the error.
|
|
1251
|
-
*/
|
|
1252
|
-
const chain: <E2, A, B>(f: (a: A) => TaskResult<E2, B>) => <E1 = never>(data: TaskResult<E1, A>) => TaskResult<E1 | E2, B>;
|
|
1253
|
-
/**
|
|
1254
|
-
* Extracts the value from a Task.Result by providing handlers for both cases.
|
|
1255
|
-
*/
|
|
1256
|
-
const fold: <E, A, B>(onErr: (e: E) => B, onOk: (a: A) => B) => (data: TaskResult<E, A>) => Task<B>;
|
|
1257
|
-
/**
|
|
1258
|
-
* Pattern matches on a Task.Result, returning a Task of the result.
|
|
1259
|
-
*/
|
|
1260
|
-
const match: <E, A, B>(cases: {
|
|
1261
|
-
err: (e: E) => B;
|
|
1262
|
-
ok: (a: A) => B;
|
|
1263
|
-
}) => (data: TaskResult<E, A>) => Task<B>;
|
|
1264
|
-
/**
|
|
1265
|
-
* Recovers from an error by providing a fallback Task.Result.
|
|
1266
|
-
* The fallback can produce a different success type, widening the result to `Task.Result<E, A | B>`.
|
|
1267
|
-
*/
|
|
1268
|
-
const recover: <E, B>(fallback: (e: E) => TaskResult<E, B>) => <A>(data: TaskResult<E, A>) => TaskResult<E, A | B>;
|
|
1269
|
-
/**
|
|
1270
|
-
* Recovers from an error unless the predicate `isBlocked` returns true for that error.
|
|
1271
|
-
* The fallback can produce a different success type, widening the result to `Task.Result<E, A | B>`.
|
|
1272
|
-
*
|
|
1273
|
-
* @example
|
|
1274
|
-
* ```ts
|
|
1275
|
-
* pipe(
|
|
1276
|
-
* fetchTask,
|
|
1277
|
-
* Task.Result.recoverUnless(
|
|
1278
|
-
* (e) => e === "fatal",
|
|
1279
|
-
* () => Task.Result.ok("fallback")
|
|
1280
|
-
* )
|
|
1281
|
-
* );
|
|
1282
|
-
* ```
|
|
1283
|
-
*/
|
|
1284
|
-
const recoverUnless: <E, B>(isBlocked: (e: E) => boolean, fallback: (e: E) => TaskResult<E, B>) => <A>(data: TaskResult<E, A>) => TaskResult<E, A | B>;
|
|
1285
|
-
/**
|
|
1286
|
-
* Returns the success value or a default value if the Task.Result is an error.
|
|
1287
|
-
* The default can be a different type, widening the result to `Task<A | B>`.
|
|
1288
|
-
*/
|
|
1289
|
-
const getOrElse: <B>(defaultValue: () => B) => <E, A>(data: TaskResult<E, A>) => Task<A | B>;
|
|
1290
|
-
/**
|
|
1291
|
-
* Executes a side effect on the success value without changing the Task.Result.
|
|
1292
|
-
* Useful for logging or debugging.
|
|
1293
|
-
*/
|
|
1294
|
-
const tap: <E, A>(f: (a: A) => void) => (data: TaskResult<E, A>) => TaskResult<E, A>;
|
|
1295
|
-
/**
|
|
1296
|
-
* Executes a side effect on the error value without changing the Task.Result.
|
|
1297
|
-
* Useful for logging or reporting async errors.
|
|
1298
|
-
*
|
|
1299
|
-
* @example
|
|
1300
|
-
* ```ts
|
|
1301
|
-
* pipe(
|
|
1302
|
-
* fetchUser(id),
|
|
1303
|
-
* Task.Result.tapError(e => console.error("fetch failed:", e)),
|
|
1304
|
-
* Task.Result.chain(saveToCache),
|
|
1305
|
-
* )
|
|
1306
|
-
* ```
|
|
1307
|
-
*/
|
|
1308
|
-
const tapError: <E, A>(f: (e: E) => void) => (data: TaskResult<E, A>) => TaskResult<E, A>;
|
|
1309
|
-
/**
|
|
1310
|
-
* Applies a function wrapped in a Task.Result to a value wrapped in a Task.Result.
|
|
1311
|
-
* Both Tasks run in parallel.
|
|
1312
|
-
*/
|
|
1313
|
-
const ap: <E, A>(arg: TaskResult<E, A>) => <B>(data: TaskResult<E, (a: A) => B>) => TaskResult<E, B>;
|
|
1314
|
-
/**
|
|
1315
|
-
* Executes a `Task.Result` with an optional signal, returning `Promise<Result<E, A>>`.
|
|
1316
|
-
* Use as a terminal step in a `pipe` chain.
|
|
1317
|
-
*
|
|
1318
|
-
* @example
|
|
1319
|
-
* ```ts
|
|
1320
|
-
* const controller = new AbortController();
|
|
1321
|
-
* const result = await pipe(
|
|
1322
|
-
* fetchUser("42"),
|
|
1323
|
-
* Task.Result.chain(user => fetchPosts(user.id)),
|
|
1324
|
-
* Task.Result.run(controller.signal),
|
|
1325
|
-
* );
|
|
1326
|
-
* if (Result.is.ok(result)) render(result.value);
|
|
1327
|
-
* ```
|
|
1328
|
-
*/
|
|
1329
|
-
const run: (signal?: AbortSignal) => <E, A>(task: TaskResult<E, A>) => Deferred<Result<E, A>>;
|
|
1330
|
-
/**
|
|
1331
|
-
* Converts a Task.Result value into an object containing a single property.
|
|
1332
|
-
* Initiates the pipeline accumulator record.
|
|
1333
|
-
*
|
|
1334
|
-
* @example
|
|
1335
|
-
* ```ts
|
|
1336
|
-
* pipe(Task.Result.ok(42), Task.Result.bindTo("value")); // Task.Result({ value: 42 })
|
|
1337
|
-
* ```
|
|
1338
|
-
*/
|
|
1339
|
-
const bindTo: <K extends string>(key: K) => <E, A>(data: TaskResult<E, A>) => TaskResult<E, { [P in K]: A; }>;
|
|
1340
|
-
/**
|
|
1341
|
-
* Evaluates a new Task.Result using the current accumulator and attaches the output to a new key.
|
|
1342
|
-
*
|
|
1343
|
-
* @example
|
|
1344
|
-
* ```ts
|
|
1345
|
-
* pipe(
|
|
1346
|
-
* Task.Result.ok({ a: 1 }),
|
|
1347
|
-
* Task.Result.bind("b", ({ a }) => Task.Result.ok(a + 1))
|
|
1348
|
-
* ); // Task.Result({ a: 1, b: 2 })
|
|
1349
|
-
* ```
|
|
1350
|
-
*/
|
|
1351
|
-
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; }>;
|
|
1218
|
+
Maybe: <E, A>(data: Validation<E, A>) => Maybe<A>;
|
|
1219
|
+
};
|
|
1352
1220
|
/**
|
|
1353
|
-
* Combines
|
|
1354
|
-
*
|
|
1355
|
-
*
|
|
1221
|
+
* Combines two independent Validation instances into a tuple.
|
|
1222
|
+
* If both are Passed, returns Passed with both values as a tuple.
|
|
1223
|
+
* If either is Failed, accumulates errors from both sides.
|
|
1356
1224
|
*
|
|
1357
1225
|
* @example
|
|
1358
1226
|
* ```ts
|
|
1359
|
-
*
|
|
1360
|
-
*
|
|
1361
|
-
*
|
|
1362
|
-
*
|
|
1363
|
-
* ```
|
|
1364
|
-
*/
|
|
1365
|
-
const struct: <E, R extends Record<string, any>>(fields: { [K in keyof R]: TaskResult<E, R[K]>; }) => TaskResult<E, R>;
|
|
1366
|
-
/**
|
|
1367
|
-
* Retries a fallible Task.Result according to a RetryPolicy.
|
|
1368
|
-
* If the task succeeds, returns Ok immediately.
|
|
1369
|
-
* If the task fails, retries up to policy.attempts times with delays generated by policy.
|
|
1227
|
+
* Validation.product(
|
|
1228
|
+
* Validation.make.passed("alice"),
|
|
1229
|
+
* Validation.make.passed(30)
|
|
1230
|
+
* ); // Passed(["alice", 30])
|
|
1370
1231
|
*
|
|
1371
|
-
*
|
|
1372
|
-
*
|
|
1373
|
-
*
|
|
1374
|
-
*
|
|
1232
|
+
* Validation.product(
|
|
1233
|
+
* Validation.make.failed("Name required"),
|
|
1234
|
+
* Validation.make.failed("Age must be >= 0")
|
|
1235
|
+
* ); // Failed(["Name required", "Age must be >= 0"])
|
|
1375
1236
|
* ```
|
|
1376
1237
|
*/
|
|
1377
|
-
|
|
1238
|
+
product: <E, A, B>(first: Validation<E, A>, second: Validation<E, B>) => Validation<E, readonly [A, B]>;
|
|
1378
1239
|
/**
|
|
1379
|
-
*
|
|
1380
|
-
*
|
|
1240
|
+
* Combines a non-empty list of Validation instances, accumulating all errors.
|
|
1241
|
+
* If all are Passed, returns Passed with all values collected into an array.
|
|
1242
|
+
* If any are Failed, returns Failed with all accumulated errors.
|
|
1381
1243
|
*
|
|
1382
1244
|
* @example
|
|
1383
1245
|
* ```ts
|
|
1384
|
-
*
|
|
1246
|
+
* Validation.productAll([
|
|
1247
|
+
* validateName(name),
|
|
1248
|
+
* validateEmail(email),
|
|
1249
|
+
* validateAge(age)
|
|
1250
|
+
* ]);
|
|
1251
|
+
* // Passed([name, email, age]) or Failed([...all errors])
|
|
1385
1252
|
* ```
|
|
1386
1253
|
*/
|
|
1387
|
-
|
|
1254
|
+
productAll: <E, A>(data: NonEmptyArr<Validation<E, A>>) => Validation<E, readonly A[]>;
|
|
1388
1255
|
/**
|
|
1389
|
-
*
|
|
1390
|
-
*
|
|
1256
|
+
* Combines a record of Validations into a single Validation of a record.
|
|
1257
|
+
* Accumulates all failed branches' errors.
|
|
1391
1258
|
*
|
|
1392
1259
|
* @example
|
|
1393
1260
|
* ```ts
|
|
1394
|
-
*
|
|
1395
|
-
*
|
|
1396
|
-
*
|
|
1397
|
-
* );
|
|
1398
|
-
* ```
|
|
1399
|
-
*/
|
|
1400
|
-
const timeout: <E2>(options: {
|
|
1401
|
-
duration: Duration;
|
|
1402
|
-
onTimeout: () => E2;
|
|
1403
|
-
}) => <E1 = never, A = unknown>(task: TaskResult<E1, A>) => TaskResult<E1 | E2, A>;
|
|
1404
|
-
/**
|
|
1405
|
-
* Runs a list of fallible tasks in parallel and collects all outcomes (`Ok` and `Err`)
|
|
1406
|
-
* without short-circuiting on failure.
|
|
1261
|
+
* Validation.struct({
|
|
1262
|
+
* name: Validation.make.passed("Alice"),
|
|
1263
|
+
* age: Validation.make.passed(30)
|
|
1264
|
+
* }); // Passed({ name: "Alice", age: 30 })
|
|
1407
1265
|
*
|
|
1408
|
-
*
|
|
1409
|
-
*
|
|
1410
|
-
*
|
|
1411
|
-
* // [
|
|
1266
|
+
* Validation.struct({
|
|
1267
|
+
* name: Validation.make.failed("Name required"),
|
|
1268
|
+
* age: Validation.make.failed("Age must be >= 0")
|
|
1269
|
+
* }); // Failed(["Name required", "Age must be >= 0"])
|
|
1412
1270
|
* ```
|
|
1413
1271
|
*/
|
|
1414
|
-
|
|
1415
|
-
}
|
|
1272
|
+
struct: <E, R extends Record<string, any>>(fields: { [K in keyof R]: Validation<E, R[K]>; }) => Validation<E, R>;
|
|
1273
|
+
};
|
|
1416
1274
|
|
|
1275
|
+
type _CoreMaybe<A> = Maybe<A>;
|
|
1276
|
+
type _CoreResult<E, A> = Result<E, A>;
|
|
1277
|
+
type _CoreValidation<E, A> = Validation<E, A>;
|
|
1417
1278
|
/**
|
|
1418
|
-
* A
|
|
1419
|
-
*
|
|
1420
|
-
*
|
|
1279
|
+
* A lazy async computation that always resolves.
|
|
1280
|
+
*
|
|
1281
|
+
* Two guarantees:
|
|
1282
|
+
* - **Lazy** — nothing starts until you call it.
|
|
1283
|
+
* - **Infallible** — it never rejects. If failure is possible, encode it in the
|
|
1284
|
+
* return type using `Task.Result<E, A>` instead.
|
|
1285
|
+
*
|
|
1286
|
+
* An optional `AbortSignal` can be passed at the call site. Combinators like
|
|
1287
|
+
* `retry`, `pollUntil`, and `timeout` thread it automatically to every inner
|
|
1288
|
+
* operation. Existing tasks that ignore the signal continue to work unchanged.
|
|
1289
|
+
*
|
|
1290
|
+
* Calling a Task returns a `Deferred<A>` — a one-shot async value that supports
|
|
1291
|
+
* `await` but has no `.catch()`, `.finally()`, or chainable `.then()`.
|
|
1292
|
+
*
|
|
1293
|
+
* **Consuming a Task:**
|
|
1294
|
+
*
|
|
1295
|
+
* Use `await task()` to run it and get the value directly:
|
|
1296
|
+
* ```ts
|
|
1297
|
+
* const value: number = await task();
|
|
1298
|
+
* ```
|
|
1299
|
+
*
|
|
1300
|
+
* When you need an explicit `Promise<A>` (e.g. for a third-party API), convert
|
|
1301
|
+
* the `Deferred` with `Deferred.to.Promise`:
|
|
1302
|
+
* ```ts
|
|
1303
|
+
* const p: Promise<number> = Deferred.to.Promise(task());
|
|
1304
|
+
* ```
|
|
1421
1305
|
*
|
|
1422
1306
|
* @example
|
|
1423
1307
|
* ```ts
|
|
1424
|
-
* const
|
|
1425
|
-
* name.length > 0
|
|
1426
|
-
* ? Task.Validation.passed(name)
|
|
1427
|
-
* : Task.Validation.failed("Name is required");
|
|
1308
|
+
* const getTimestamp: Task<number> = Task.resolve(Date.now());
|
|
1428
1309
|
*
|
|
1429
|
-
* //
|
|
1430
|
-
* pipe(
|
|
1431
|
-
*
|
|
1432
|
-
* Task.
|
|
1433
|
-
*
|
|
1434
|
-
*
|
|
1435
|
-
* //
|
|
1310
|
+
* // Nothing runs yet — getTimestamp is just a description
|
|
1311
|
+
* const formatted = pipe(
|
|
1312
|
+
* getTimestamp,
|
|
1313
|
+
* Task.map(ts => new Date(ts).toISOString())
|
|
1314
|
+
* );
|
|
1315
|
+
*
|
|
1316
|
+
* // Execute when ready
|
|
1317
|
+
* const result = await formatted();
|
|
1436
1318
|
* ```
|
|
1437
1319
|
*/
|
|
1438
|
-
type
|
|
1439
|
-
declare
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
/**
|
|
1452
|
-
* Creates a failed Task.Validation with a single error.
|
|
1453
|
-
*
|
|
1454
|
-
* @example
|
|
1455
|
-
* ```ts
|
|
1456
|
-
* const task = Task.Validation.make.failed("invalid");
|
|
1457
|
-
* const res = await task(); // Failed(["invalid"])
|
|
1458
|
-
* ```
|
|
1459
|
-
*/
|
|
1460
|
-
const failed: <E, A = never>(error: E) => TaskValidation<E, A>;
|
|
1461
|
-
/**
|
|
1462
|
-
* Creates a failed Task.Validation from multiple errors.
|
|
1463
|
-
*
|
|
1464
|
-
* @example
|
|
1465
|
-
* ```ts
|
|
1466
|
-
* const task = Task.Validation.make.failedAll(["err1", "err2"]);
|
|
1467
|
-
* const res = await task(); // Failed(["err1", "err2"])
|
|
1468
|
-
* ```
|
|
1469
|
-
*/
|
|
1470
|
-
const failedAll: <E, A = never>(errors: NonEmptyArr<E>) => TaskValidation<E, A>;
|
|
1471
|
-
}
|
|
1472
|
-
const passed: <E = never, A = unknown>(value: A) => TaskValidation<E, A>;
|
|
1473
|
-
const failed: <E, A = never>(error: E) => TaskValidation<E, A>;
|
|
1474
|
-
const failedAll: <E, A = never>(errors: NonEmptyArr<E>) => TaskValidation<E, A>;
|
|
1475
|
-
namespace from {
|
|
1476
|
-
/**
|
|
1477
|
-
* Lifts a Validation into a Task.Validation.
|
|
1478
|
-
*
|
|
1479
|
-
* @example
|
|
1480
|
-
* ```ts
|
|
1481
|
-
* Task.Validation.from.Validation(Validation.make.passed(42));
|
|
1482
|
-
* ```
|
|
1483
|
-
*/
|
|
1484
|
-
const Validation: <E, A>(validation: Validation<E, A>) => TaskValidation<E, A>;
|
|
1485
|
-
/**
|
|
1486
|
-
* Creates a Task.Validation from a nullable value.
|
|
1487
|
-
* If the value is null or undefined, returns Failed with the error from onNull.
|
|
1488
|
-
* Otherwise, returns Passed.
|
|
1489
|
-
*
|
|
1490
|
-
* @example
|
|
1491
|
-
* ```ts
|
|
1492
|
-
* Task.Validation.from.nullable(() => "missing")(42); // resolves to Passed(42)
|
|
1493
|
-
* Task.Validation.from.nullable(() => "missing")(null); // resolves to Failed(["missing"])
|
|
1494
|
-
* ```
|
|
1495
|
-
*/
|
|
1496
|
-
const nullable: <E>(onNull: () => E) => <A>(value: A | null | undefined) => TaskValidation<E, A>;
|
|
1497
|
-
/**
|
|
1498
|
-
* Creates a Task.Validation from a Maybe.
|
|
1499
|
-
* Some becomes Passed, None becomes Failed with the error from onNone.
|
|
1500
|
-
*
|
|
1501
|
-
* @example
|
|
1502
|
-
* ```ts
|
|
1503
|
-
* Task.Validation.from.Maybe(() => "empty")(Maybe.make.some(42)); // resolves to Passed(42)
|
|
1504
|
-
* Task.Validation.from.Maybe(() => "empty")(Maybe.make.none()); // resolves to Failed(["empty"])
|
|
1505
|
-
* ```
|
|
1506
|
-
*/
|
|
1507
|
-
const Maybe: <E>(onNone: () => E) => <A>(maybe: Maybe<A>) => TaskValidation<E, A>;
|
|
1508
|
-
/**
|
|
1509
|
-
* Creates a Task.Validation from a Result.
|
|
1510
|
-
* Ok becomes Passed, Err(e) becomes Failed([e]).
|
|
1511
|
-
*
|
|
1512
|
-
* @example
|
|
1513
|
-
* ```ts
|
|
1514
|
-
* Task.Validation.from.Result(Result.make.ok(42)); // resolves to Passed(42)
|
|
1515
|
-
* Task.Validation.from.Result(Result.make.err("bad")); // resolves to Failed(["bad"])
|
|
1516
|
-
* ```
|
|
1517
|
-
*/
|
|
1518
|
-
const Result: <E, A>(result: Result<E, A>) => TaskValidation<E, A>;
|
|
1519
|
-
}
|
|
1520
|
-
namespace to {
|
|
1521
|
-
/**
|
|
1522
|
-
* Converts a `Task.Validation` to a `Task.Result`, combining accumulated errors using `combineErrors`.
|
|
1523
|
-
* `Passed(a)` becomes `Ok(a)`; `Failed(errors)` becomes `Err(combineErrors(errors))`.
|
|
1524
|
-
*
|
|
1525
|
-
* @example
|
|
1526
|
-
* ```ts
|
|
1527
|
-
* Task.Validation.to.Result((errors) => errors.join(", "))(validationTask);
|
|
1528
|
-
* ```
|
|
1529
|
-
*/
|
|
1530
|
-
const Result: <E1, E2, A>(combineErrors: (errors: NonEmptyArr<E1>) => E2) => (data: TaskValidation<E1, A>) => TaskResult<E2, A>;
|
|
1320
|
+
type Task<A> = (signal?: AbortSignal) => Deferred<A>;
|
|
1321
|
+
declare const Task: {
|
|
1322
|
+
/**
|
|
1323
|
+
* Creates a Task that immediately resolves to the given value.
|
|
1324
|
+
*
|
|
1325
|
+
* @example
|
|
1326
|
+
* ```ts
|
|
1327
|
+
* const task = Task.resolve(42);
|
|
1328
|
+
* const value = await task(); // 42
|
|
1329
|
+
* ```
|
|
1330
|
+
*/
|
|
1331
|
+
resolve: <A>(value: A) => Task<A>;
|
|
1332
|
+
from: {
|
|
1531
1333
|
/**
|
|
1532
|
-
*
|
|
1533
|
-
*
|
|
1334
|
+
* Creates a Task from a lazy synchronous thunk.
|
|
1335
|
+
* Unlike `Task.resolve(f())`, `from.sync` does not evaluate `f` until the Task is called.
|
|
1534
1336
|
*
|
|
1535
1337
|
* @example
|
|
1536
1338
|
* ```ts
|
|
1537
|
-
* Task.
|
|
1339
|
+
* const t = Task.from.sync(() => Date.now()); // Date.now() not called yet
|
|
1340
|
+
* const ts = await t(); // called here, every time
|
|
1538
1341
|
* ```
|
|
1539
1342
|
*/
|
|
1540
|
-
|
|
1541
|
-
}
|
|
1542
|
-
/**
|
|
1543
|
-
* Creates a Task.Validation from a Promise-returning function.
|
|
1544
|
-
* Catches any errors and transforms them using the onError function.
|
|
1545
|
-
* The factory optionally receives an `AbortSignal` forwarded from the call site.
|
|
1343
|
+
sync: <A>(f: () => A) => Task<A>;
|
|
1344
|
+
};
|
|
1546
1345
|
/**
|
|
1547
|
-
*
|
|
1548
|
-
*
|
|
1549
|
-
* The thunk optionally receives an `AbortSignal` forwarded from the call site.
|
|
1346
|
+
* Wraps a Promise-returning thunk that may throw or reject,
|
|
1347
|
+
* trapping errors with a fallback function and returning a guaranteed `Task<A>`.
|
|
1550
1348
|
*
|
|
1551
1349
|
* @example
|
|
1552
1350
|
* ```ts
|
|
1553
|
-
* const loadConfig = Task.
|
|
1554
|
-
* (
|
|
1555
|
-
* { onError: (
|
|
1351
|
+
* const loadConfig = Task.tryCatch(
|
|
1352
|
+
* () => configStore.get("default"),
|
|
1353
|
+
* { onError: () => DEFAULT_CONFIG }
|
|
1556
1354
|
* );
|
|
1557
1355
|
* ```
|
|
1558
1356
|
*/
|
|
1559
|
-
|
|
1560
|
-
onError: (error: unknown) =>
|
|
1561
|
-
}) =>
|
|
1562
|
-
/**
|
|
1563
|
-
* Transforms the success value inside a Task.Validation.
|
|
1564
|
-
*/
|
|
1565
|
-
const map: <E, A, B>(f: (a: A) => B) => (data: TaskValidation<E, A>) => TaskValidation<E, B>;
|
|
1357
|
+
tryCatch: <A>(f: (signal?: AbortSignal) => globalThis.Promise<A>, options: {
|
|
1358
|
+
onError: (error: unknown) => A;
|
|
1359
|
+
}) => Task<A>;
|
|
1566
1360
|
/**
|
|
1567
|
-
*
|
|
1568
|
-
* Task.Validation. Both Tasks run in parallel and errors from both sides
|
|
1569
|
-
* are accumulated.
|
|
1361
|
+
* Transforms the value inside a Task.
|
|
1570
1362
|
*
|
|
1571
1363
|
* @example
|
|
1572
1364
|
* ```ts
|
|
1573
1365
|
* pipe(
|
|
1574
|
-
* Task.
|
|
1575
|
-
* Task.
|
|
1576
|
-
*
|
|
1577
|
-
* )();
|
|
1366
|
+
* Task.resolve(5),
|
|
1367
|
+
* Task.map(n => n * 2)
|
|
1368
|
+
* )(); // Deferred<10>
|
|
1578
1369
|
* ```
|
|
1579
1370
|
*/
|
|
1580
|
-
|
|
1581
|
-
/**
|
|
1582
|
-
* Extracts a value from a Task.Validation by providing handlers for both cases.
|
|
1583
|
-
*/
|
|
1584
|
-
const fold: <E, A, B>(onFailed: (errors: NonEmptyArr<E>) => B, onPassed: (a: A) => B) => (data: TaskValidation<E, A>) => Task<B>;
|
|
1371
|
+
map: <A, B>(f: (a: A) => B) => (data: Task<A>) => Task<B>;
|
|
1585
1372
|
/**
|
|
1586
|
-
*
|
|
1373
|
+
* Chains Task computations. Passes the resolved value of the first Task to f.
|
|
1587
1374
|
*
|
|
1588
1375
|
* @example
|
|
1589
1376
|
* ```ts
|
|
1377
|
+
* const readUserId: Task<string> = Task.resolve(session.userId);
|
|
1378
|
+
* const loadPrefs = (id: string): Task<Preferences> =>
|
|
1379
|
+
* Task.resolve(prefsCache.get(id));
|
|
1380
|
+
*
|
|
1590
1381
|
* pipe(
|
|
1591
|
-
*
|
|
1592
|
-
* Task.
|
|
1593
|
-
*
|
|
1594
|
-
* failed: errors => showErrors(errors)
|
|
1595
|
-
* })
|
|
1596
|
-
* )();
|
|
1382
|
+
* readUserId,
|
|
1383
|
+
* Task.chain(loadPrefs)
|
|
1384
|
+
* )(); // Deferred<Preferences>
|
|
1597
1385
|
* ```
|
|
1598
1386
|
*/
|
|
1599
|
-
|
|
1600
|
-
passed: (a: A) => B;
|
|
1601
|
-
failed: (errors: NonEmptyArr<E>) => B;
|
|
1602
|
-
}) => (data: TaskValidation<E, A>) => Task<B>;
|
|
1603
|
-
/**
|
|
1604
|
-
* Returns the success value or a default value if the Task.Validation is failed.
|
|
1605
|
-
* The default can be a different type, widening the result to `Task<A | B>`.
|
|
1606
|
-
*/
|
|
1607
|
-
const getOrElse: <B>(defaultValue: () => B) => <E, A>(data: TaskValidation<E, A>) => Task<A | B>;
|
|
1608
|
-
/**
|
|
1609
|
-
* Executes a side effect on the success value without changing the Task.Validation.
|
|
1610
|
-
* Useful for logging or debugging.
|
|
1611
|
-
*/
|
|
1612
|
-
const tap: <E, A>(f: (a: A) => void) => (data: TaskValidation<E, A>) => TaskValidation<E, A>;
|
|
1613
|
-
/**
|
|
1614
|
-
* Recovers from a Failed state by providing a fallback Task.Validation.
|
|
1615
|
-
* The fallback receives the accumulated error list so callers can inspect which errors occurred.
|
|
1616
|
-
* The fallback can produce a different success type, widening the result to `Task.Validation<E, A | B>`.
|
|
1617
|
-
*/
|
|
1618
|
-
const recover: <E, B>(fallback: (errors: NonEmptyArr<E>) => TaskValidation<E, B>) => <A>(data: TaskValidation<E, A>) => TaskValidation<E, A | B>;
|
|
1619
|
-
/**
|
|
1620
|
-
* Recovers from a Failed state unless the predicate `isBlocked` returns true for the accumulated errors.
|
|
1621
|
-
* The fallback receives the accumulated errors and can produce a different success type, widening the result to `Task.Validation<E, A | B>`.
|
|
1622
|
-
*
|
|
1623
|
-
* @example
|
|
1624
|
-
* ```ts
|
|
1625
|
-
* pipe(
|
|
1626
|
-
* validationTask,
|
|
1627
|
-
* Task.Validation.recoverUnless(
|
|
1628
|
-
* (errors) => errors.includes("fatal"),
|
|
1629
|
-
* (errors) => Task.Validation.passed("fallback")
|
|
1630
|
-
* )
|
|
1631
|
-
* );
|
|
1632
|
-
* ```
|
|
1633
|
-
*/
|
|
1634
|
-
const recoverUnless: <E, B>(isBlocked: (errors: NonEmptyArr<E>) => boolean, fallback: (errors: NonEmptyArr<E>) => TaskValidation<E, B>) => <A>(data: TaskValidation<E, A>) => TaskValidation<E, A | B>;
|
|
1635
|
-
/**
|
|
1636
|
-
* Runs two Task.Validations concurrently and combines their results into a tuple.
|
|
1637
|
-
* If both are Passed, returns Passed with both values. If either fails, accumulates
|
|
1638
|
-
* errors from both sides.
|
|
1639
|
-
*
|
|
1640
|
-
* @example
|
|
1641
|
-
* ```ts
|
|
1642
|
-
* await Task.Validation.product(
|
|
1643
|
-
* validateName(form.name),
|
|
1644
|
-
* validateAge(form.age),
|
|
1645
|
-
* )(); // Passed(["Alice", 30]) or Failed([...errors])
|
|
1646
|
-
* ```
|
|
1647
|
-
*/
|
|
1648
|
-
const product: <E, A, B>(first: TaskValidation<E, A>, second: TaskValidation<E, B>) => TaskValidation<E, readonly [A, B]>;
|
|
1649
|
-
/**
|
|
1650
|
-
* Runs all Task.Validations concurrently and collects results.
|
|
1651
|
-
* If all are Passed, returns Passed with all values as an array.
|
|
1652
|
-
* If any fail, returns Failed with all accumulated errors.
|
|
1653
|
-
*
|
|
1654
|
-
* @example
|
|
1655
|
-
* ```ts
|
|
1656
|
-
* await Task.Validation.productAll([
|
|
1657
|
-
* validateName(form.name),
|
|
1658
|
-
* validateEmail(form.email),
|
|
1659
|
-
* validateAge(form.age),
|
|
1660
|
-
* ])(); // Passed([name, email, age]) or Failed([...all errors])
|
|
1661
|
-
* ```
|
|
1662
|
-
*/
|
|
1663
|
-
const productAll: <E, A>(data: NonEmptyArr<TaskValidation<E, A>>) => TaskValidation<E, readonly A[]>;
|
|
1664
|
-
/**
|
|
1665
|
-
* Transforms all accumulated errors inside a Task.Validation.
|
|
1666
|
-
*
|
|
1667
|
-
* @example
|
|
1668
|
-
* ```ts
|
|
1669
|
-
* pipe(
|
|
1670
|
-
* Task.Validation.failed("oops"),
|
|
1671
|
-
* Task.Validation.mapError(e => e.toUpperCase())
|
|
1672
|
-
* ); // Task.Validation(Failed(["OOPS"]))
|
|
1673
|
-
* ```
|
|
1674
|
-
*/
|
|
1675
|
-
const mapError: <E, F, A>(f: (e: E) => F) => (data: TaskValidation<E, A>) => TaskValidation<F, A>;
|
|
1676
|
-
/**
|
|
1677
|
-
* Executes a side effect on the accumulated errors without changing the Task.Validation.
|
|
1678
|
-
*
|
|
1679
|
-
* @example
|
|
1680
|
-
* ```ts
|
|
1681
|
-
* pipe(
|
|
1682
|
-
* Task.Validation.failed("invalid name"),
|
|
1683
|
-
* Task.Validation.tapError(errs => logger.error(errs))
|
|
1684
|
-
* );
|
|
1685
|
-
* ```
|
|
1686
|
-
*/
|
|
1687
|
-
const tapError: <E, A>(f: (errors: NonEmptyArr<E>) => void) => (data: TaskValidation<E, A>) => TaskValidation<E, A>;
|
|
1688
|
-
/**
|
|
1689
|
-
* Combines a record of Task.Validations into a single Task.Validation of a record.
|
|
1690
|
-
* Evaluates fields in parallel and accumulates all validation errors.
|
|
1691
|
-
*
|
|
1692
|
-
* @example
|
|
1693
|
-
* ```ts
|
|
1694
|
-
* Task.Validation.struct({
|
|
1695
|
-
* name: Task.Validation.passed("Alice"),
|
|
1696
|
-
* age: Task.Validation.passed(30)
|
|
1697
|
-
* }); // Task.Validation({ name: "Alice", age: 30 })
|
|
1698
|
-
* ```
|
|
1699
|
-
*/
|
|
1700
|
-
const struct: <E, R extends Record<string, any>>(fields: { [K in keyof R]: TaskValidation<E, R[K]>; }) => TaskValidation<E, R>;
|
|
1701
|
-
/**
|
|
1702
|
-
* Creates a memoized version of a Task.Validation. The task is executed at most once on first call,
|
|
1703
|
-
* and its resolved Validation is cached for all subsequent calls.
|
|
1704
|
-
*
|
|
1705
|
-
* @example
|
|
1706
|
-
* ```ts
|
|
1707
|
-
* const validate = Task.Validation.memoize(validateFormTask);
|
|
1708
|
-
* ```
|
|
1709
|
-
*/
|
|
1710
|
-
const memoize: <E, A>(task: TaskValidation<E, A>) => TaskValidation<E, A>;
|
|
1711
|
-
}
|
|
1712
|
-
|
|
1713
|
-
/**
|
|
1714
|
-
* A lazy async computation that always resolves.
|
|
1715
|
-
*
|
|
1716
|
-
* Two guarantees:
|
|
1717
|
-
* - **Lazy** — nothing starts until you call it.
|
|
1718
|
-
* - **Infallible** — it never rejects. If failure is possible, encode it in the
|
|
1719
|
-
* return type using `Task.Result<E, A>` instead.
|
|
1720
|
-
*
|
|
1721
|
-
* An optional `AbortSignal` can be passed at the call site. Combinators like
|
|
1722
|
-
* `retry`, `pollUntil`, and `timeout` thread it automatically to every inner
|
|
1723
|
-
* operation. Existing tasks that ignore the signal continue to work unchanged.
|
|
1724
|
-
*
|
|
1725
|
-
* Calling a Task returns a `Deferred<A>` — a one-shot async value that supports
|
|
1726
|
-
* `await` but has no `.catch()`, `.finally()`, or chainable `.then()`.
|
|
1727
|
-
*
|
|
1728
|
-
* **Consuming a Task:**
|
|
1729
|
-
*
|
|
1730
|
-
* Use `await task()` to run it and get the value directly:
|
|
1731
|
-
* ```ts
|
|
1732
|
-
* const value: number = await task();
|
|
1733
|
-
* ```
|
|
1734
|
-
*
|
|
1735
|
-
* When you need an explicit `Promise<A>` (e.g. for a third-party API), convert
|
|
1736
|
-
* the `Deferred` with `Deferred.to.Promise`:
|
|
1737
|
-
* ```ts
|
|
1738
|
-
* const p: Promise<number> = Deferred.to.Promise(task());
|
|
1739
|
-
* ```
|
|
1740
|
-
*
|
|
1741
|
-
* @example
|
|
1742
|
-
* ```ts
|
|
1743
|
-
* const getTimestamp: Task<number> = Task.resolve(Date.now());
|
|
1744
|
-
*
|
|
1745
|
-
* // Nothing runs yet — getTimestamp is just a description
|
|
1746
|
-
* const formatted = pipe(
|
|
1747
|
-
* getTimestamp,
|
|
1748
|
-
* Task.map(ts => new Date(ts).toISOString())
|
|
1749
|
-
* );
|
|
1750
|
-
*
|
|
1751
|
-
* // Execute when ready
|
|
1752
|
-
* const result = await formatted();
|
|
1753
|
-
* ```
|
|
1754
|
-
*/
|
|
1755
|
-
type Task<A> = (signal?: AbortSignal) => Deferred<A>;
|
|
1756
|
-
declare namespace Task {
|
|
1757
|
-
/**
|
|
1758
|
-
* Creates a Task that immediately resolves to the given value.
|
|
1759
|
-
*
|
|
1760
|
-
* @example
|
|
1761
|
-
* ```ts
|
|
1762
|
-
* const task = Task.resolve(42);
|
|
1763
|
-
* const value = await task(); // 42
|
|
1764
|
-
* ```
|
|
1765
|
-
*/
|
|
1766
|
-
const resolve: <A>(value: A) => Task<A>;
|
|
1767
|
-
namespace from {
|
|
1768
|
-
/**
|
|
1769
|
-
* Creates a Task from a lazy synchronous thunk.
|
|
1770
|
-
* Unlike `Task.resolve(f())`, `from.sync` does not evaluate `f` until the Task is called.
|
|
1771
|
-
*
|
|
1772
|
-
* @example
|
|
1773
|
-
* ```ts
|
|
1774
|
-
* const t = Task.from.sync(() => Date.now()); // Date.now() not called yet
|
|
1775
|
-
* const ts = await t(); // called here, every time
|
|
1776
|
-
* ```
|
|
1777
|
-
*/
|
|
1778
|
-
const sync: <A>(f: () => A) => Task<A>;
|
|
1779
|
-
}
|
|
1780
|
-
/**
|
|
1781
|
-
* Wraps a Promise-returning thunk that may throw or reject,
|
|
1782
|
-
* trapping errors with a fallback function and returning a guaranteed `Task<A>`.
|
|
1783
|
-
*
|
|
1784
|
-
* @example
|
|
1785
|
-
* ```ts
|
|
1786
|
-
* const loadConfig = Task.tryCatch(
|
|
1787
|
-
* () => configStore.get("default"),
|
|
1788
|
-
* { onError: () => DEFAULT_CONFIG }
|
|
1789
|
-
* );
|
|
1790
|
-
* ```
|
|
1791
|
-
*/
|
|
1792
|
-
const tryCatch: <A>(f: (signal?: AbortSignal) => globalThis.Promise<A>, options: {
|
|
1793
|
-
onError: (error: unknown) => A;
|
|
1794
|
-
}) => Task<A>;
|
|
1795
|
-
/**
|
|
1796
|
-
* Transforms the value inside a Task.
|
|
1797
|
-
*
|
|
1798
|
-
* @example
|
|
1799
|
-
* ```ts
|
|
1800
|
-
* pipe(
|
|
1801
|
-
* Task.resolve(5),
|
|
1802
|
-
* Task.map(n => n * 2)
|
|
1803
|
-
* )(); // Deferred<10>
|
|
1804
|
-
* ```
|
|
1805
|
-
*/
|
|
1806
|
-
const map: <A, B>(f: (a: A) => B) => (data: Task<A>) => Task<B>;
|
|
1807
|
-
/**
|
|
1808
|
-
* Chains Task computations. Passes the resolved value of the first Task to f.
|
|
1809
|
-
*
|
|
1810
|
-
* @example
|
|
1811
|
-
* ```ts
|
|
1812
|
-
* const readUserId: Task<string> = Task.resolve(session.userId);
|
|
1813
|
-
* const loadPrefs = (id: string): Task<Preferences> =>
|
|
1814
|
-
* Task.resolve(prefsCache.get(id));
|
|
1815
|
-
*
|
|
1816
|
-
* pipe(
|
|
1817
|
-
* readUserId,
|
|
1818
|
-
* Task.chain(loadPrefs)
|
|
1819
|
-
* )(); // Deferred<Preferences>
|
|
1820
|
-
* ```
|
|
1821
|
-
*/
|
|
1822
|
-
const chain: <A, B>(f: (a: A) => Task<B>) => (data: Task<A>) => Task<B>;
|
|
1387
|
+
chain: <A, B>(f: (a: A) => Task<B>) => (data: Task<A>) => Task<B>;
|
|
1823
1388
|
/**
|
|
1824
1389
|
* Applies a function wrapped in a Task to a value wrapped in a Task.
|
|
1825
1390
|
* Both Tasks run in parallel.
|
|
1826
1391
|
*
|
|
1827
|
-
* @example
|
|
1828
|
-
* ```ts
|
|
1829
|
-
* const add = (a: number) => (b: number) => a + b;
|
|
1830
|
-
* pipe(
|
|
1831
|
-
* Task.resolve(add),
|
|
1832
|
-
* Task.ap(Task.resolve(5)),
|
|
1833
|
-
* Task.ap(Task.resolve(3))
|
|
1834
|
-
* )(); // Deferred<8>
|
|
1835
|
-
* ```
|
|
1836
|
-
*/
|
|
1837
|
-
|
|
1838
|
-
/**
|
|
1839
|
-
* Executes a side effect on the value without changing the Task.
|
|
1840
|
-
* Useful for logging or debugging.
|
|
1841
|
-
*
|
|
1842
|
-
* @example
|
|
1843
|
-
* ```ts
|
|
1844
|
-
* pipe(
|
|
1845
|
-
* loadConfig,
|
|
1846
|
-
* Task.tap(cfg => console.log("Config:", cfg)),
|
|
1847
|
-
* Task.map(buildReport)
|
|
1848
|
-
* );
|
|
1849
|
-
* ```
|
|
1850
|
-
*/
|
|
1851
|
-
const tap: <A>(f: (a: A) => void) => (data: Task<A>) => Task<A>;
|
|
1852
|
-
/**
|
|
1853
|
-
* Runs multiple Tasks in parallel and collects their results.
|
|
1854
|
-
*
|
|
1855
|
-
* @example
|
|
1856
|
-
* ```ts
|
|
1857
|
-
* Task.all([loadConfig, detectLocale, loadTheme])();
|
|
1858
|
-
* // Deferred<[Config, string, Theme]>
|
|
1859
|
-
* ```
|
|
1860
|
-
*/
|
|
1861
|
-
const all: <T extends readonly Task<unknown>[]>(tasks: T) => Task<{ [K in keyof T]: T[K] extends Task<infer A> ? A : never; }>;
|
|
1862
|
-
/**
|
|
1863
|
-
* Delays the execution of a Task by the specified duration.
|
|
1864
|
-
* Useful for debouncing or rate limiting.
|
|
1865
|
-
*
|
|
1866
|
-
* @example
|
|
1867
|
-
* ```ts
|
|
1868
|
-
* pipe(
|
|
1869
|
-
* Task.resolve(42),
|
|
1870
|
-
* Task.delay(Duration.seconds(1))
|
|
1871
|
-
* )(); // Resolves after 1 second
|
|
1872
|
-
* ```
|
|
1873
|
-
*/
|
|
1874
|
-
const delay: (duration: Duration) => <A>(data: Task<A>) => Task<A>;
|
|
1875
|
-
/**
|
|
1876
|
-
* Runs a Task a fixed number of times sequentially, collecting all results into an array.
|
|
1877
|
-
* An optional delay duration can be inserted between runs.
|
|
1878
|
-
*
|
|
1879
|
-
* @example
|
|
1880
|
-
* ```ts
|
|
1881
|
-
* pipe(
|
|
1882
|
-
* pollSensor,
|
|
1883
|
-
* Task.repeat({ times: 5, delay: Duration.seconds(1) })
|
|
1884
|
-
* )(); // Task<Reading[]> — 5 readings, one per second
|
|
1885
|
-
* ```
|
|
1886
|
-
*/
|
|
1887
|
-
const repeat: (options: {
|
|
1888
|
-
times: number;
|
|
1889
|
-
delay?: Duration;
|
|
1890
|
-
}) => <A>(task: Task<A>) => Task<readonly A[]>;
|
|
1891
|
-
/**
|
|
1892
|
-
* Runs a Task repeatedly until the result satisfies a predicate, returning that result.
|
|
1893
|
-
* An optional delay duration can be inserted between runs.
|
|
1894
|
-
* An optional `maxAttempts` cap stops the loop after N calls — the last value is returned
|
|
1895
|
-
* regardless of whether the predicate was satisfied.
|
|
1896
|
-
*
|
|
1897
|
-
* @example
|
|
1898
|
-
* ```ts
|
|
1899
|
-
* pipe(
|
|
1900
|
-
* checkStatus,
|
|
1901
|
-
* Task.repeatUntil({ when: (s) => s === "ready", delay: Duration.milliseconds(500) })
|
|
1902
|
-
* )(); // polls every 500ms until status is "ready"
|
|
1903
|
-
* ```
|
|
1904
|
-
*/
|
|
1905
|
-
const repeatUntil: <A>(options: {
|
|
1906
|
-
when: (a: A) => boolean;
|
|
1907
|
-
delay?: Duration;
|
|
1908
|
-
maxAttempts?: number;
|
|
1909
|
-
}) => (task: Task<A>) => Task<A>;
|
|
1910
|
-
/**
|
|
1911
|
-
* Resolves with the value of the first Task to complete. All Tasks start
|
|
1912
|
-
* immediately. When one resolves, the other tasks are cancelled (aborted)
|
|
1913
|
-
* downstream.
|
|
1914
|
-
*
|
|
1915
|
-
* @example
|
|
1916
|
-
* ```ts
|
|
1917
|
-
* const fast = Task.resolve("fast");
|
|
1918
|
-
* const slow = Task.delay(Duration.milliseconds(200))(Task.resolve("slow"));
|
|
1919
|
-
*
|
|
1920
|
-
* await Task.race([fast, slow])(); // "fast"
|
|
1921
|
-
* ```
|
|
1922
|
-
*/
|
|
1923
|
-
const race: <A>(tasks: ReadonlyArray<Task<A>>) => Task<A>;
|
|
1924
|
-
/**
|
|
1925
|
-
* Runs an array of Tasks concurrently and collects their results in an array.
|
|
1926
|
-
* Forward-propagates the call site's AbortSignal to all subtasks concurrently.
|
|
1927
|
-
*
|
|
1928
|
-
* @example
|
|
1929
|
-
* ```ts
|
|
1930
|
-
* Task.sequence([loadConfig, detectLocale, loadTheme])();
|
|
1931
|
-
* // Deferred<[Config, string, Theme]>
|
|
1932
|
-
* ```
|
|
1933
|
-
*/
|
|
1934
|
-
const sequence: <A>(tasks: ReadonlyArray<Task<A>>) => Task<ReadonlyArray<A>>;
|
|
1935
|
-
/**
|
|
1936
|
-
* Runs an array of Tasks one at a time in order, collecting all results.
|
|
1937
|
-
* Each Task starts only after the previous one resolves.
|
|
1938
|
-
*
|
|
1939
|
-
* @example
|
|
1940
|
-
* ```ts
|
|
1941
|
-
* let log: number[] = [];
|
|
1942
|
-
* const makeTask = (n: number) => Task.resolve(n);
|
|
1943
|
-
*
|
|
1944
|
-
* await Task.sequential([makeTask(1), makeTask(2), makeTask(3)])();
|
|
1945
|
-
* // log = [1, 2, 3] — tasks ran in order
|
|
1946
|
-
* ```
|
|
1947
|
-
*/
|
|
1948
|
-
const sequential: <A>(tasks: ReadonlyArray<Task<A>>) => Task<ReadonlyArray<A>>;
|
|
1949
|
-
/**
|
|
1950
|
-
* Converts a `Task<A>` into a `Task<Result<E, A>>`, resolving to `Err` if the
|
|
1951
|
-
* Task does not complete within the given duration. The inner Task receives an
|
|
1952
|
-
* `AbortSignal` that fires when the deadline passes, so asynchronous operations
|
|
1953
|
-
* that accept a signal are cancelled rather than left dangling.
|
|
1954
|
-
*
|
|
1955
|
-
* @example
|
|
1956
|
-
* ```ts
|
|
1957
|
-
* pipe(
|
|
1958
|
-
* heavyComputation,
|
|
1959
|
-
* Task.timeout({ duration: Duration.seconds(5), onTimeout: () => "timed out" }),
|
|
1960
|
-
* Task.Result.chain(processResult)
|
|
1961
|
-
* );
|
|
1962
|
-
* ```
|
|
1963
|
-
*/
|
|
1964
|
-
const timeout: <E>(options: {
|
|
1965
|
-
duration: Duration;
|
|
1966
|
-
onTimeout: () => E;
|
|
1967
|
-
}) => <A>(task: Task<A>) => Task<Result<E, A>>;
|
|
1968
|
-
/**
|
|
1969
|
-
* Creates a Task paired with an `abort` handle. Calling `abort()` cancels the
|
|
1970
|
-
* current in-flight call immediately. Unlike a one-shot abort, calling `task()`
|
|
1971
|
-
* again after `abort()` starts a fresh call with a new signal.
|
|
1972
|
-
*
|
|
1973
|
-
* Each invocation of `task()` automatically cancels the previous in-flight call,
|
|
1974
|
-
* making it safe to call repeatedly (e.g. on user input) without leaking promises.
|
|
1975
|
-
*
|
|
1976
|
-
* If an outer signal is also present (passed at the call site), aborting it
|
|
1977
|
-
* propagates into the internal controller.
|
|
1978
|
-
*
|
|
1979
|
-
* @example
|
|
1980
|
-
* ```ts
|
|
1981
|
-
* const { task: poll, abort } = Task.abortable(
|
|
1982
|
-
* (signal) => waitForEvent(bus, "ready", { signal }),
|
|
1983
|
-
* );
|
|
1984
|
-
*
|
|
1985
|
-
* onUnmount(abort);
|
|
1986
|
-
* await poll();
|
|
1987
|
-
* ```
|
|
1988
|
-
*/
|
|
1989
|
-
const abortable: <A>(factory: (signal: AbortSignal) => Thenable<A>) => {
|
|
1990
|
-
task: Task<A>;
|
|
1991
|
-
abort: () => void;
|
|
1992
|
-
};
|
|
1993
|
-
/**
|
|
1994
|
-
* Executes a task with an optional signal. Use as a terminal step in a `pipe` chain.
|
|
1995
|
-
*
|
|
1996
|
-
* @example
|
|
1997
|
-
* ```ts
|
|
1998
|
-
* const name = await pipe(
|
|
1999
|
-
* loadConfig,
|
|
2000
|
-
* Task.map(config => config.name),
|
|
2001
|
-
* Task.run(),
|
|
2002
|
-
* );
|
|
2003
|
-
* ```
|
|
2004
|
-
*/
|
|
2005
|
-
const run: (signal?: AbortSignal) => <A>(task: Task<A>) => Deferred<A>;
|
|
2006
|
-
/**
|
|
2007
|
-
* Converts a Task value into an object containing a single property.
|
|
2008
|
-
* Initiates the pipeline accumulator record.
|
|
2009
|
-
*
|
|
2010
|
-
* @example
|
|
2011
|
-
* ```ts
|
|
2012
|
-
* pipe(Task.resolve(42), Task.bindTo("value")); // Task({ value: 42 })
|
|
2013
|
-
* ```
|
|
2014
|
-
*/
|
|
2015
|
-
const bindTo: <K extends string>(key: K) => <A>(data: Task<A>) => Task<{ [P in K]: A; }>;
|
|
2016
|
-
/**
|
|
2017
|
-
* Evaluates a new Task using the current accumulator and attaches the output to a new key.
|
|
2018
|
-
*
|
|
2019
|
-
* @example
|
|
2020
|
-
* ```ts
|
|
2021
|
-
* pipe(
|
|
2022
|
-
* Task.resolve({ a: 1 }),
|
|
2023
|
-
* Task.bind("b", ({ a }) => Task.resolve(a + 1))
|
|
2024
|
-
* ); // Task({ a: 1, b: 2 })
|
|
2025
|
-
* ```
|
|
2026
|
-
*/
|
|
2027
|
-
const bind: <K extends string, A, B>(key: K, f: (a: A) => Task<B>) => (data: Task<A>) => Task<A & { [P in K]: B; }>;
|
|
2028
|
-
/**
|
|
2029
|
-
* Creates a memoized version of a Task. The task is executed at most once on first call,
|
|
2030
|
-
* and its resolved value is cached for all subsequent calls.
|
|
2031
|
-
*
|
|
2032
|
-
* @example
|
|
2033
|
-
* ```ts
|
|
2034
|
-
* const loadToken = Task.memoize(loadAuthToken);
|
|
2035
|
-
* const token1 = await loadToken(); // loads token
|
|
2036
|
-
* const token2 = await loadToken(); // returns cached token immediately
|
|
2037
|
-
* ```
|
|
2038
|
-
*/
|
|
2039
|
-
const memoize: <A>(task: Task<A>) => Task<A>;
|
|
2040
|
-
/**
|
|
2041
|
-
* Monitors progress of a Task by calling `onProgress(0)` before execution and `onProgress(1)` upon completion.
|
|
2042
|
-
*
|
|
2043
|
-
* @example
|
|
2044
|
-
* ```ts
|
|
2045
|
-
* const taskWithProgress = pipe(
|
|
2046
|
-
* readTask,
|
|
2047
|
-
* Task.withProgress((ratio) => console.log(`Progress: ${ratio * 100}%`))
|
|
2048
|
-
* );
|
|
2049
|
-
* ```
|
|
2050
|
-
*/
|
|
2051
|
-
const withProgress: <A>(onProgress: (ratio: number) => void) => (task: Task<A>) => Task<A>;
|
|
2052
|
-
type LabeledTask<L extends string, A> = Task<A> & {
|
|
2053
|
-
readonly label: L;
|
|
2054
|
-
};
|
|
2055
|
-
/**
|
|
2056
|
-
* Attaches a read-only `.label` property to a Task, preserving the literal string generic type for IDE tooltips.
|
|
2057
|
-
*
|
|
2058
|
-
* @example
|
|
2059
|
-
* ```ts
|
|
2060
|
-
* const labeledTask = pipe(readTask, Task.withLabel("readUser"));
|
|
2061
|
-
* console.log(labeledTask.label); // "readUser"
|
|
2062
|
-
* ```
|
|
2063
|
-
*/
|
|
2064
|
-
const withLabel: <L extends string>(label: L) => <A>(task: Task<A>) => LabeledTask<L, A>;
|
|
2065
|
-
type Maybe<A> = TaskMaybe<A>;
|
|
2066
|
-
const Maybe: typeof TaskMaybe;
|
|
2067
|
-
type Result<E, A> = TaskResult<E, A>;
|
|
2068
|
-
const Result: typeof TaskResult;
|
|
2069
|
-
type Validation<E, A> = TaskValidation<E, A>;
|
|
2070
|
-
const Validation: typeof TaskValidation;
|
|
2071
|
-
}
|
|
2072
|
-
|
|
2073
|
-
type Passed<A> = WithKind<"Passed"> & WithValue<A>;
|
|
2074
|
-
type Failed<E> = WithKind<"Failed"> & WithErrors<E>;
|
|
2075
|
-
/**
|
|
2076
|
-
* Validation represents a value that is either passed with a success value,
|
|
2077
|
-
* or failed with accumulated errors.
|
|
2078
|
-
* Unlike Result, Validation can accumulate multiple errors instead of short-circuiting.
|
|
2079
|
-
*
|
|
2080
|
-
* Use Validation when you need to collect all errors (e.g., form validation).
|
|
2081
|
-
* Use Result when you want to fail fast on the first error.
|
|
2082
|
-
*
|
|
2083
|
-
* @example
|
|
2084
|
-
* ```ts
|
|
2085
|
-
* const validateName = (name: string): Validation<string, string> =>
|
|
2086
|
-
* name.length > 0 ? Validation.make.passed(name) : Validation.make.failed("Name is required");
|
|
2087
|
-
*
|
|
2088
|
-
* const validateAge = (age: number): Validation<string, number> =>
|
|
2089
|
-
* age >= 0 ? Validation.make.passed(age) : Validation.make.failed("Age must be positive");
|
|
2090
|
-
*
|
|
2091
|
-
* // Accumulates all errors using ap
|
|
2092
|
-
* pipe(
|
|
2093
|
-
* Validation.make.passed((name: string) => (age: number) => ({ name, age })),
|
|
2094
|
-
* Validation.ap(validateName("")),
|
|
2095
|
-
* Validation.ap(validateAge(-1))
|
|
2096
|
-
* );
|
|
2097
|
-
* // Failed(["Name is required", "Age must be positive"])
|
|
2098
|
-
* ```
|
|
2099
|
-
*/
|
|
2100
|
-
type Validation<E, A> = Passed<A> | Failed<E>;
|
|
2101
|
-
declare namespace Validation {
|
|
2102
|
-
namespace make {
|
|
2103
|
-
/**
|
|
2104
|
-
* Wraps a value in a passed Validation.
|
|
2105
|
-
*
|
|
2106
|
-
* @example
|
|
2107
|
-
* ```ts
|
|
2108
|
-
* Validation.make.passed(42); // Passed(42)
|
|
2109
|
-
* ```
|
|
2110
|
-
*/
|
|
2111
|
-
const passed: <E, A>(value: A) => Validation<E, A>;
|
|
2112
|
-
/**
|
|
2113
|
-
* Creates a failed Validation from a single error.
|
|
2114
|
-
*
|
|
2115
|
-
* @example
|
|
2116
|
-
* ```ts
|
|
2117
|
-
* Validation.make.failed("Invalid input");
|
|
2118
|
-
* ```
|
|
2119
|
-
*/
|
|
2120
|
-
const failed: <E>(error: E) => Failed<E>;
|
|
2121
|
-
/**
|
|
2122
|
-
* Creates a failed Validation from multiple errors.
|
|
2123
|
-
*
|
|
2124
|
-
* @example
|
|
2125
|
-
* ```ts
|
|
2126
|
-
* Validation.make.failedAll(["Invalid input"]);
|
|
2127
|
-
* ```
|
|
2128
|
-
*/
|
|
2129
|
-
const failedAll: <E>(errors: NonEmptyArr<E>) => Failed<E>;
|
|
2130
|
-
}
|
|
2131
|
-
namespace is {
|
|
2132
|
-
/**
|
|
2133
|
-
* Type guard that checks if a Validation is passed.
|
|
2134
|
-
*
|
|
2135
|
-
* @example
|
|
2136
|
-
* ```ts
|
|
2137
|
-
* const v = Validation.make.passed(42);
|
|
2138
|
-
* if (Validation.is.passed(v)) {
|
|
2139
|
-
* console.log(v.value); // 42
|
|
2140
|
-
* }
|
|
2141
|
-
* ```
|
|
2142
|
-
*/
|
|
2143
|
-
const passed: <E, A>(data: Validation<E, A>) => data is Passed<A>;
|
|
2144
|
-
/**
|
|
2145
|
-
* Type guard that checks if a Validation is failed.
|
|
2146
|
-
*
|
|
2147
|
-
* @example
|
|
2148
|
-
* ```ts
|
|
2149
|
-
* const v = Validation.make.failed("invalid");
|
|
2150
|
-
* if (Validation.is.failed(v)) {
|
|
2151
|
-
* console.log(v.errors); // ["invalid"]
|
|
2152
|
-
* }
|
|
2153
|
-
* ```
|
|
2154
|
-
*/
|
|
2155
|
-
const failed: <E, A>(data: Validation<E, A>) => data is Failed<E>;
|
|
2156
|
-
}
|
|
2157
|
-
/**
|
|
2158
|
-
* Creates a Validation from a synchronous thunk that may throw.
|
|
2159
|
-
* Catches any errors and transforms them using the `onError` function into a Failed validation.
|
|
2160
|
-
*
|
|
2161
|
-
* @example
|
|
2162
|
-
* ```ts
|
|
2163
|
-
* const result = Validation.tryCatch(
|
|
2164
|
-
* () => JSON.parse(rawString),
|
|
2165
|
-
* { onError: (e) => `Parse error: ${e}` }
|
|
2166
|
-
* );
|
|
2167
|
-
* ```
|
|
2168
|
-
*/
|
|
2169
|
-
const tryCatch: <E, A>(f: () => A, options: {
|
|
2170
|
-
onError: (e: unknown) => E;
|
|
2171
|
-
}) => Validation<E, A>;
|
|
2172
|
-
namespace from {
|
|
2173
|
-
/**
|
|
2174
|
-
* Creates a Validation from a predicate applied to a value.
|
|
2175
|
-
* Returns Passed if the predicate passes, Failed from `onFalse` otherwise.
|
|
2176
|
-
*
|
|
2177
|
-
* @example
|
|
2178
|
-
* ```ts
|
|
2179
|
-
* const validateName = Validation.from.Predicate(
|
|
2180
|
-
* (s: string) => s.length > 0,
|
|
2181
|
-
* () => "Name is required"
|
|
2182
|
-
* );
|
|
2183
|
-
*
|
|
2184
|
-
* validateName("Alice"); // Passed("Alice")
|
|
2185
|
-
* validateName(""); // Failed(["Name is required"])
|
|
2186
|
-
* ```
|
|
2187
|
-
*/
|
|
2188
|
-
const Predicate: <E, A>(pred: (a: A) => boolean, onFalse: (a: A) => E) => (a: A) => Validation<E, A>;
|
|
2189
|
-
/**
|
|
2190
|
-
* Creates a Validation from a nullable value.
|
|
2191
|
-
* If the value is null or undefined, returns Failed with the error from onNull.
|
|
2192
|
-
* Otherwise, returns Passed.
|
|
2193
|
-
*
|
|
2194
|
-
* @example
|
|
2195
|
-
* ```ts
|
|
2196
|
-
* pipe(null, Validation.from.nullable(() => "is null")); // Failed(["is null"])
|
|
2197
|
-
* pipe(42, Validation.from.nullable(() => "is null")); // Passed(42)
|
|
2198
|
-
* ```
|
|
2199
|
-
*/
|
|
2200
|
-
const nullable: <E>(onNull: () => E) => <A>(value: A | null | undefined) => Validation<E, A>;
|
|
2201
|
-
/**
|
|
2202
|
-
* Creates a Validation from a Maybe.
|
|
2203
|
-
* If the Maybe is None, returns Failed with the error from onNone.
|
|
2204
|
-
* Otherwise, returns Passed.
|
|
2205
|
-
*
|
|
2206
|
-
* @example
|
|
2207
|
-
* ```ts
|
|
2208
|
-
* pipe(Maybe.make.none(), Validation.from.Maybe(() => "is none")); // Failed(["is none"])
|
|
2209
|
-
* pipe(Maybe.make.some(42), Validation.from.Maybe(() => "is none")); // Passed(42)
|
|
2210
|
-
* ```
|
|
2211
|
-
*/
|
|
2212
|
-
const Maybe: <E>(onNone: () => E) => <A>(maybe: Maybe<A>) => Validation<E, A>;
|
|
2213
|
-
/**
|
|
2214
|
-
* Converts a `Result` to a `Validation`. `Ok` becomes `Passed`; `Err(e)` becomes `Failed([e])`.
|
|
2215
|
-
*
|
|
2216
|
-
* Useful when bridging from error-short-circuiting `Result` pipelines into
|
|
2217
|
-
* error-accumulating `Validation` pipelines.
|
|
2218
|
-
*
|
|
2219
|
-
* @example
|
|
2220
|
-
* ```ts
|
|
2221
|
-
* Validation.from.Result(Result.make.ok(42)); // Passed(42)
|
|
2222
|
-
* Validation.from.Result(Result.make.err("bad")); // Failed(["bad"])
|
|
2223
|
-
* ```
|
|
2224
|
-
*/
|
|
2225
|
-
const Result: <E, A>(data: Result<E, A>) => Validation<E, A>;
|
|
2226
|
-
}
|
|
1392
|
+
* @example
|
|
1393
|
+
* ```ts
|
|
1394
|
+
* const add = (a: number) => (b: number) => a + b;
|
|
1395
|
+
* pipe(
|
|
1396
|
+
* Task.resolve(add),
|
|
1397
|
+
* Task.ap(Task.resolve(5)),
|
|
1398
|
+
* Task.ap(Task.resolve(3))
|
|
1399
|
+
* )(); // Deferred<8>
|
|
1400
|
+
* ```
|
|
1401
|
+
*/
|
|
1402
|
+
ap: <A>(arg: Task<A>) => <B>(data: Task<(a: A) => B>) => Task<B>;
|
|
2227
1403
|
/**
|
|
2228
|
-
*
|
|
1404
|
+
* Executes a side effect on the value without changing the Task.
|
|
1405
|
+
* Useful for logging or debugging.
|
|
2229
1406
|
*
|
|
2230
1407
|
* @example
|
|
2231
1408
|
* ```ts
|
|
2232
|
-
* pipe(
|
|
2233
|
-
*
|
|
1409
|
+
* pipe(
|
|
1410
|
+
* loadConfig,
|
|
1411
|
+
* Task.tap(cfg => console.log("Config:", cfg)),
|
|
1412
|
+
* Task.map(buildReport)
|
|
1413
|
+
* );
|
|
2234
1414
|
* ```
|
|
2235
1415
|
*/
|
|
2236
|
-
|
|
1416
|
+
tap: <A>(f: (a: A) => void) => (data: Task<A>) => Task<A>;
|
|
2237
1417
|
/**
|
|
2238
|
-
*
|
|
1418
|
+
* Runs multiple Tasks in parallel and collects their results.
|
|
2239
1419
|
*
|
|
2240
1420
|
* @example
|
|
2241
1421
|
* ```ts
|
|
2242
|
-
*
|
|
1422
|
+
* Task.all([loadConfig, detectLocale, loadTheme])();
|
|
1423
|
+
* // Deferred<[Config, string, Theme]>
|
|
2243
1424
|
* ```
|
|
2244
1425
|
*/
|
|
2245
|
-
|
|
1426
|
+
all: <T extends readonly Task<unknown>[]>(tasks: T) => Task<{ [K in keyof T]: T[K] extends Task<infer A> ? A : never; }>;
|
|
2246
1427
|
/**
|
|
2247
|
-
*
|
|
2248
|
-
*
|
|
1428
|
+
* Delays the execution of a Task by the specified duration.
|
|
1429
|
+
* Useful for debouncing or rate limiting.
|
|
2249
1430
|
*
|
|
2250
1431
|
* @example
|
|
2251
1432
|
* ```ts
|
|
2252
|
-
* const add = (a: number) => (b: number) => a + b;
|
|
2253
1433
|
* pipe(
|
|
2254
|
-
*
|
|
2255
|
-
*
|
|
2256
|
-
*
|
|
2257
|
-
*
|
|
1434
|
+
* Task.resolve(42),
|
|
1435
|
+
* Task.delay(Duration.seconds(1))
|
|
1436
|
+
* )(); // Resolves after 1 second
|
|
1437
|
+
* ```
|
|
1438
|
+
*/
|
|
1439
|
+
delay: (duration: Duration) => <A>(data: Task<A>) => Task<A>;
|
|
1440
|
+
/**
|
|
1441
|
+
* Runs a Task a fixed number of times sequentially, collecting all results into an array.
|
|
1442
|
+
* An optional delay duration can be inserted between runs.
|
|
2258
1443
|
*
|
|
1444
|
+
* @example
|
|
1445
|
+
* ```ts
|
|
2259
1446
|
* pipe(
|
|
2260
|
-
*
|
|
2261
|
-
*
|
|
2262
|
-
*
|
|
2263
|
-
* ); // Failed(["bad a", "bad b"])
|
|
1447
|
+
* pollSensor,
|
|
1448
|
+
* Task.repeat({ times: 5, delay: Duration.seconds(1) })
|
|
1449
|
+
* )(); // Task<Reading[]> — 5 readings, one per second
|
|
2264
1450
|
* ```
|
|
2265
1451
|
*/
|
|
2266
|
-
|
|
1452
|
+
repeat: (options: {
|
|
1453
|
+
times: number;
|
|
1454
|
+
delay?: Duration;
|
|
1455
|
+
}) => <A>(task: Task<A>) => Task<readonly A[]>;
|
|
2267
1456
|
/**
|
|
2268
|
-
*
|
|
2269
|
-
*
|
|
1457
|
+
* Runs a Task repeatedly until the result satisfies a predicate, returning that result.
|
|
1458
|
+
* An optional delay duration can be inserted between runs.
|
|
1459
|
+
* An optional `maxAttempts` cap stops the loop after N calls — the last value is returned
|
|
1460
|
+
* regardless of whether the predicate was satisfied.
|
|
2270
1461
|
*
|
|
2271
1462
|
* @example
|
|
2272
1463
|
* ```ts
|
|
2273
|
-
*
|
|
2274
|
-
*
|
|
2275
|
-
*
|
|
1464
|
+
* pipe(
|
|
1465
|
+
* checkStatus,
|
|
1466
|
+
* Task.repeatUntil({ when: (s) => s === "ready", delay: Duration.milliseconds(500) })
|
|
1467
|
+
* )(); // polls every 500ms until status is "ready"
|
|
2276
1468
|
* ```
|
|
2277
1469
|
*/
|
|
2278
|
-
|
|
1470
|
+
repeatUntil: <A>(options: {
|
|
1471
|
+
when: (a: A) => boolean;
|
|
1472
|
+
delay?: Duration;
|
|
1473
|
+
maxAttempts?: number;
|
|
1474
|
+
}) => (task: Task<A>) => Task<A>;
|
|
2279
1475
|
/**
|
|
2280
|
-
*
|
|
1476
|
+
* Resolves with the value of the first Task to complete. All Tasks start
|
|
1477
|
+
* immediately. When one resolves, the other tasks are cancelled (aborted)
|
|
1478
|
+
* downstream.
|
|
2281
1479
|
*
|
|
2282
1480
|
* @example
|
|
2283
1481
|
* ```ts
|
|
2284
|
-
*
|
|
2285
|
-
*
|
|
2286
|
-
*
|
|
2287
|
-
*
|
|
2288
|
-
* value => `Value: ${value}`
|
|
2289
|
-
* )
|
|
2290
|
-
* );
|
|
1482
|
+
* const fast = Task.resolve("fast");
|
|
1483
|
+
* const slow = Task.delay(Duration.milliseconds(200))(Task.resolve("slow"));
|
|
1484
|
+
*
|
|
1485
|
+
* await Task.race([fast, slow])(); // "fast"
|
|
2291
1486
|
* ```
|
|
2292
1487
|
*/
|
|
2293
|
-
|
|
1488
|
+
race: <A>(tasks: ReadonlyArray<Task<A>>) => Task<A>;
|
|
2294
1489
|
/**
|
|
2295
|
-
*
|
|
1490
|
+
* Runs an array of Tasks concurrently and collects their results in an array.
|
|
1491
|
+
* Forward-propagates the call site's AbortSignal to all subtasks concurrently.
|
|
2296
1492
|
*
|
|
2297
1493
|
* @example
|
|
2298
1494
|
* ```ts
|
|
2299
|
-
*
|
|
2300
|
-
*
|
|
2301
|
-
* Validation.match({
|
|
2302
|
-
* passed: value => `Got ${value}`,
|
|
2303
|
-
* failed: errors => `Failed: ${errors.join(", ")}`
|
|
2304
|
-
* })
|
|
2305
|
-
* );
|
|
1495
|
+
* Task.sequence([loadConfig, detectLocale, loadTheme])();
|
|
1496
|
+
* // Deferred<[Config, string, Theme]>
|
|
2306
1497
|
* ```
|
|
2307
1498
|
*/
|
|
2308
|
-
|
|
2309
|
-
passed: (a: A) => B;
|
|
2310
|
-
failed: (errors: NonEmptyArr<E>) => B;
|
|
2311
|
-
}) => (data: Validation<E, A>) => B;
|
|
1499
|
+
sequence: <A>(tasks: ReadonlyArray<Task<A>>) => Task<ReadonlyArray<A>>;
|
|
2312
1500
|
/**
|
|
2313
|
-
*
|
|
2314
|
-
*
|
|
1501
|
+
* Runs an array of Tasks one at a time in order, collecting all results.
|
|
1502
|
+
* Each Task starts only after the previous one resolves.
|
|
2315
1503
|
*
|
|
2316
1504
|
* @example
|
|
2317
1505
|
* ```ts
|
|
2318
|
-
*
|
|
2319
|
-
*
|
|
2320
|
-
*
|
|
1506
|
+
* let log: number[] = [];
|
|
1507
|
+
* const makeTask = (n: number) => Task.resolve(n);
|
|
1508
|
+
*
|
|
1509
|
+
* await Task.sequential([makeTask(1), makeTask(2), makeTask(3)])();
|
|
1510
|
+
* // log = [1, 2, 3] — tasks ran in order
|
|
2321
1511
|
* ```
|
|
2322
1512
|
*/
|
|
2323
|
-
|
|
1513
|
+
sequential: <A>(tasks: ReadonlyArray<Task<A>>) => Task<ReadonlyArray<A>>;
|
|
2324
1514
|
/**
|
|
2325
|
-
*
|
|
1515
|
+
* Converts a `Task<A>` into a `Task<Result<E, A>>`, resolving to `Err` if the
|
|
1516
|
+
* Task does not complete within the given duration. The inner Task receives an
|
|
1517
|
+
* `AbortSignal` that fires when the deadline passes, so asynchronous operations
|
|
1518
|
+
* that accept a signal are cancelled rather than left dangling.
|
|
2326
1519
|
*
|
|
2327
1520
|
* @example
|
|
2328
1521
|
* ```ts
|
|
2329
1522
|
* pipe(
|
|
2330
|
-
*
|
|
2331
|
-
*
|
|
2332
|
-
*
|
|
1523
|
+
* heavyComputation,
|
|
1524
|
+
* Task.timeout({ duration: Duration.seconds(5), onTimeout: () => "timed out" }),
|
|
1525
|
+
* Task.Result.chain(processResult)
|
|
2333
1526
|
* );
|
|
2334
1527
|
* ```
|
|
2335
1528
|
*/
|
|
2336
|
-
|
|
1529
|
+
timeout: <E>(options: {
|
|
1530
|
+
duration: Duration;
|
|
1531
|
+
onTimeout: () => E;
|
|
1532
|
+
}) => <A>(task: Task<A>) => Task<Result<E, A>>;
|
|
2337
1533
|
/**
|
|
2338
|
-
*
|
|
2339
|
-
*
|
|
1534
|
+
* Creates a Task paired with an `abort` handle. Calling `abort()` cancels the
|
|
1535
|
+
* current in-flight call immediately. Unlike a one-shot abort, calling `task()`
|
|
1536
|
+
* again after `abort()` starts a fresh call with a new signal.
|
|
1537
|
+
*
|
|
1538
|
+
* Each invocation of `task()` automatically cancels the previous in-flight call,
|
|
1539
|
+
* making it safe to call repeatedly (e.g. on user input) without leaking promises.
|
|
1540
|
+
*
|
|
1541
|
+
* If an outer signal is also present (passed at the call site), aborting it
|
|
1542
|
+
* propagates into the internal controller.
|
|
2340
1543
|
*
|
|
2341
1544
|
* @example
|
|
2342
1545
|
* ```ts
|
|
2343
|
-
*
|
|
2344
|
-
*
|
|
2345
|
-
* Validation.tapError(errors => console.error("validation failed:", errors)),
|
|
2346
|
-
* Validation.map(toUser)
|
|
1546
|
+
* const { task: poll, abort } = Task.abortable(
|
|
1547
|
+
* (signal) => waitForEvent(bus, "ready", { signal }),
|
|
2347
1548
|
* );
|
|
1549
|
+
*
|
|
1550
|
+
* onUnmount(abort);
|
|
1551
|
+
* await poll();
|
|
2348
1552
|
* ```
|
|
2349
1553
|
*/
|
|
2350
|
-
|
|
1554
|
+
abortable: <A>(factory: (signal: AbortSignal) => Thenable<A>) => {
|
|
1555
|
+
task: Task<A>;
|
|
1556
|
+
abort: () => void;
|
|
1557
|
+
};
|
|
2351
1558
|
/**
|
|
2352
|
-
*
|
|
2353
|
-
*
|
|
2354
|
-
*
|
|
1559
|
+
* Executes a task with an optional signal. Use as a terminal step in a `pipe` chain.
|
|
1560
|
+
*
|
|
1561
|
+
* @example
|
|
1562
|
+
* ```ts
|
|
1563
|
+
* const name = await pipe(
|
|
1564
|
+
* loadConfig,
|
|
1565
|
+
* Task.map(config => config.name),
|
|
1566
|
+
* Task.run(),
|
|
1567
|
+
* );
|
|
1568
|
+
* ```
|
|
2355
1569
|
*/
|
|
2356
|
-
|
|
1570
|
+
run: (signal?: AbortSignal) => <A>(task: Task<A>) => Deferred<A>;
|
|
2357
1571
|
/**
|
|
2358
|
-
*
|
|
2359
|
-
*
|
|
1572
|
+
* Converts a Task value into an object containing a single property.
|
|
1573
|
+
* Initiates the pipeline accumulator record.
|
|
2360
1574
|
*
|
|
2361
1575
|
* @example
|
|
2362
1576
|
* ```ts
|
|
2363
|
-
* pipe(
|
|
2364
|
-
* Validation.make.failed("field-error"),
|
|
2365
|
-
* Validation.recoverUnless(e => e === "fatal", () => Validation.make.passed(0))
|
|
2366
|
-
* ); // Passed(0)
|
|
1577
|
+
* pipe(Task.resolve(42), Task.bindTo("value")); // Task({ value: 42 })
|
|
2367
1578
|
* ```
|
|
2368
1579
|
*/
|
|
2369
|
-
|
|
2370
|
-
namespace to {
|
|
2371
|
-
/**
|
|
2372
|
-
* Converts a Validation to a Result.
|
|
2373
|
-
* Passed becomes Ok.
|
|
2374
|
-
* Direct call converts Failed to Err with accumulated error list `NonEmptyArr<E>`.
|
|
2375
|
-
* Curried call converts Failed to Err with combined error `E2` via `combineErrors`.
|
|
2376
|
-
*
|
|
2377
|
-
* @example
|
|
2378
|
-
* ```ts
|
|
2379
|
-
* Validation.to.Result(Validation.make.passed(42)); // Ok(42)
|
|
2380
|
-
* Validation.to.Result(Validation.make.failed("oops")); // Err(["oops"])
|
|
2381
|
-
* pipe(Validation.make.failed("oops"), Validation.to.Result(errors => errors.join(", "))); // Err("oops")
|
|
2382
|
-
* ```
|
|
2383
|
-
*/
|
|
2384
|
-
function Result<E1, E2, A>(combineErrors: (errors: NonEmptyArr<E1>) => E2): (val: Validation<E1, A>) => Result<E2, A>;
|
|
2385
|
-
function Result<E, A>(data: Validation<E, A>): Result<NonEmptyArr<E>, A>;
|
|
2386
|
-
/**
|
|
2387
|
-
* Converts a Validation to a Maybe. `Passed` becomes `Some`; `Failed` becomes `None`
|
|
2388
|
-
* (errors are discarded).
|
|
2389
|
-
*
|
|
2390
|
-
* @example
|
|
2391
|
-
* ```ts
|
|
2392
|
-
* Validation.to.Maybe(Validation.make.passed(42)); // Some(42)
|
|
2393
|
-
* Validation.to.Maybe(Validation.make.failed("bad")); // None
|
|
2394
|
-
* ```
|
|
2395
|
-
*/
|
|
2396
|
-
const Maybe: <E, A>(data: Validation<E, A>) => Maybe<A>;
|
|
2397
|
-
}
|
|
1580
|
+
bindTo: <K extends string>(key: K) => <A>(data: Task<A>) => Task<{ [P in K]: A; }>;
|
|
2398
1581
|
/**
|
|
2399
|
-
*
|
|
2400
|
-
* If both are Passed, returns Passed with both values as a tuple.
|
|
2401
|
-
* If either is Failed, accumulates errors from both sides.
|
|
1582
|
+
* Evaluates a new Task using the current accumulator and attaches the output to a new key.
|
|
2402
1583
|
*
|
|
2403
1584
|
* @example
|
|
2404
1585
|
* ```ts
|
|
2405
|
-
*
|
|
2406
|
-
*
|
|
2407
|
-
*
|
|
2408
|
-
* ); //
|
|
2409
|
-
*
|
|
2410
|
-
* Validation.product(
|
|
2411
|
-
* Validation.make.failed("Name required"),
|
|
2412
|
-
* Validation.make.failed("Age must be >= 0")
|
|
2413
|
-
* ); // Failed(["Name required", "Age must be >= 0"])
|
|
1586
|
+
* pipe(
|
|
1587
|
+
* Task.resolve({ a: 1 }),
|
|
1588
|
+
* Task.bind("b", ({ a }) => Task.resolve(a + 1))
|
|
1589
|
+
* ); // Task({ a: 1, b: 2 })
|
|
2414
1590
|
* ```
|
|
2415
1591
|
*/
|
|
2416
|
-
|
|
1592
|
+
bind: <K extends string, A, B>(key: K, f: (a: A) => Task<B>) => (data: Task<A>) => Task<A & { [P in K]: B; }>;
|
|
2417
1593
|
/**
|
|
2418
|
-
*
|
|
2419
|
-
*
|
|
2420
|
-
* If any are Failed, returns Failed with all accumulated errors.
|
|
1594
|
+
* Creates a memoized version of a Task. The task is executed at most once on first call,
|
|
1595
|
+
* and its resolved value is cached for all subsequent calls.
|
|
2421
1596
|
*
|
|
2422
1597
|
* @example
|
|
2423
1598
|
* ```ts
|
|
2424
|
-
*
|
|
2425
|
-
*
|
|
2426
|
-
*
|
|
2427
|
-
* validateAge(age)
|
|
2428
|
-
* ]);
|
|
2429
|
-
* // Passed([name, email, age]) or Failed([...all errors])
|
|
1599
|
+
* const loadToken = Task.memoize(loadAuthToken);
|
|
1600
|
+
* const token1 = await loadToken(); // loads token
|
|
1601
|
+
* const token2 = await loadToken(); // returns cached token immediately
|
|
2430
1602
|
* ```
|
|
2431
1603
|
*/
|
|
2432
|
-
|
|
1604
|
+
memoize: <A>(task: Task<A>) => Task<A>;
|
|
2433
1605
|
/**
|
|
2434
|
-
*
|
|
2435
|
-
* Accumulates all failed branches' errors.
|
|
1606
|
+
* Monitors progress of a Task by calling `onProgress(0)` before execution and `onProgress(1)` upon completion.
|
|
2436
1607
|
*
|
|
2437
1608
|
* @example
|
|
2438
1609
|
* ```ts
|
|
2439
|
-
*
|
|
2440
|
-
*
|
|
2441
|
-
*
|
|
2442
|
-
*
|
|
1610
|
+
* const taskWithProgress = pipe(
|
|
1611
|
+
* readTask,
|
|
1612
|
+
* Task.withProgress((ratio) => console.log(`Progress: ${ratio * 100}%`))
|
|
1613
|
+
* );
|
|
1614
|
+
* ```
|
|
1615
|
+
*/
|
|
1616
|
+
withProgress: <A>(onProgress: (ratio: number) => void) => (task: Task<A>) => Task<A>;
|
|
1617
|
+
/**
|
|
1618
|
+
* Attaches a read-only `.label` property to a Task, preserving the literal string generic type for IDE tooltips.
|
|
2443
1619
|
*
|
|
2444
|
-
*
|
|
2445
|
-
*
|
|
2446
|
-
*
|
|
2447
|
-
*
|
|
1620
|
+
* @example
|
|
1621
|
+
* ```ts
|
|
1622
|
+
* const labeledTask = pipe(readTask, Task.withLabel("readUser"));
|
|
1623
|
+
* console.log(labeledTask.label); // "readUser"
|
|
2448
1624
|
* ```
|
|
2449
1625
|
*/
|
|
2450
|
-
|
|
1626
|
+
withLabel: <L extends string>(label: L) => <A>(task: Task<A>) => Task.LabeledTask<L, A>;
|
|
1627
|
+
Maybe: {
|
|
1628
|
+
make: {
|
|
1629
|
+
some: <A>(value: A) => Task.Maybe<A>;
|
|
1630
|
+
none: <A = never>() => Task.Maybe<A>;
|
|
1631
|
+
};
|
|
1632
|
+
from: {
|
|
1633
|
+
Maybe: <A>(option: Maybe<A>) => Task.Maybe<A>;
|
|
1634
|
+
nullable: <A>(value: A | null | undefined) => Task.Maybe<A>;
|
|
1635
|
+
Result: <E, A>(result: Result<E, A>) => Task.Maybe<A>;
|
|
1636
|
+
Task: <A>(task: Task<A>) => Task.Maybe<A>;
|
|
1637
|
+
};
|
|
1638
|
+
tryCatch: <A>(f: (signal?: AbortSignal) => Thenable<A>) => Task.Maybe<A>;
|
|
1639
|
+
map: <A, B>(f: (a: A) => B) => (data: Task.Maybe<A>) => Task.Maybe<B>;
|
|
1640
|
+
chain: <A, B>(f: (a: A) => Task.Maybe<B>) => (data: Task.Maybe<A>) => Task.Maybe<B>;
|
|
1641
|
+
ap: <A>(arg: Task.Maybe<A>) => <B>(data: Task.Maybe<(a: A) => B>) => Task.Maybe<B>;
|
|
1642
|
+
fold: <A, B>(onNone: () => B, onSome: (a: A) => B) => (data: Task.Maybe<A>) => Task<B>;
|
|
1643
|
+
match: <A, B>(cases: {
|
|
1644
|
+
none: () => B;
|
|
1645
|
+
some: (a: A) => B;
|
|
1646
|
+
}) => (data: Task.Maybe<A>) => Task<B>;
|
|
1647
|
+
getOrElse: <B>(defaultValue: () => B) => <A>(data: Task.Maybe<A>) => Task<A | B>;
|
|
1648
|
+
tap: <A>(f: (a: A) => void) => (data: Task.Maybe<A>) => Task.Maybe<A>;
|
|
1649
|
+
filter: <A>(predicate: (a: A) => boolean) => (data: Task.Maybe<A>) => Task.Maybe<A>;
|
|
1650
|
+
to: {
|
|
1651
|
+
Result: <E>(onNone: () => E) => <A>(data: Task.Maybe<A>) => Task.Result<E, A>;
|
|
1652
|
+
};
|
|
1653
|
+
bindTo: <K extends string>(key: K) => <A>(data: Task.Maybe<A>) => Task.Maybe<{ [P in K]: A; }>;
|
|
1654
|
+
bind: <K extends string, A, B>(key: K, f: (a: A) => Task.Maybe<B>) => (data: Task.Maybe<A>) => Task.Maybe<A & { [P in K]: B; }>;
|
|
1655
|
+
recover: <B>(fallback: () => Task.Maybe<B>) => <A>(data: Task.Maybe<A>) => Task.Maybe<A | B>;
|
|
1656
|
+
struct: <R extends Record<string, any>>(fields: { [K in keyof R]: Task.Maybe<R[K]>; }) => Task.Maybe<R>;
|
|
1657
|
+
memoize: <A>(task: Task.Maybe<A>) => Task.Maybe<A>;
|
|
1658
|
+
};
|
|
1659
|
+
Result: {
|
|
1660
|
+
make: {
|
|
1661
|
+
ok: <E = never, A = unknown>(value: A) => Task.Result<E, A>;
|
|
1662
|
+
err: <E, A = never>(error: E) => Task.Result<E, A>;
|
|
1663
|
+
};
|
|
1664
|
+
from: {
|
|
1665
|
+
nullable: <E>(onNull: () => E) => <A>(value: A | null | undefined) => Task.Result<E, A>;
|
|
1666
|
+
Maybe: <E>(onNone: () => E) => <A>(maybe: Maybe<A>) => Task.Result<E, A>;
|
|
1667
|
+
Result: <E, A>(result: Result<E, A>) => Task.Result<E, A>;
|
|
1668
|
+
};
|
|
1669
|
+
to: {
|
|
1670
|
+
Maybe: <E, A>(data: Task.Result<E, A>) => Task.Maybe<A>;
|
|
1671
|
+
};
|
|
1672
|
+
tryCatch: <E, A>(f: (signal?: AbortSignal) => Thenable<A>, options: {
|
|
1673
|
+
onError: (error: unknown) => E;
|
|
1674
|
+
}) => Task.Result<E, A>;
|
|
1675
|
+
map: <E, A, B>(f: (a: A) => B) => (data: Task.Result<E, A>) => Task.Result<E, B>;
|
|
1676
|
+
mapError: <E, F, A>(f: (e: E) => F) => (data: Task.Result<E, A>) => Task.Result<F, A>;
|
|
1677
|
+
chain: <E2, A, B>(f: (a: A) => Task.Result<E2, B>) => <E1 = never>(data: Task.Result<E1, A>) => Task.Result<E1 | E2, B>;
|
|
1678
|
+
fold: <E, A, B>(onErr: (e: E) => B, onOk: (a: A) => B) => (data: Task.Result<E, A>) => Task<B>;
|
|
1679
|
+
match: <E, A, B>(cases: {
|
|
1680
|
+
err: (e: E) => B;
|
|
1681
|
+
ok: (a: A) => B;
|
|
1682
|
+
}) => (data: Task.Result<E, A>) => Task<B>;
|
|
1683
|
+
recover: <E, B>(fallback: (e: E) => Task.Result<E, B>) => <A>(data: Task.Result<E, A>) => Task.Result<E, A | B>;
|
|
1684
|
+
recoverUnless: <E, B>(isBlocked: (e: E) => boolean, fallback: (e: E) => Task.Result<E, B>) => <A>(data: Task.Result<E, A>) => Task.Result<E, A | B>;
|
|
1685
|
+
getOrElse: <B>(defaultValue: () => B) => <E, A>(data: Task.Result<E, A>) => Task<A | B>;
|
|
1686
|
+
tap: <E, A>(f: (a: A) => void) => (data: Task.Result<E, A>) => Task.Result<E, A>;
|
|
1687
|
+
tapError: <E, A>(f: (e: E) => void) => (data: Task.Result<E, A>) => Task.Result<E, A>;
|
|
1688
|
+
ap: <E, A>(arg: Task.Result<E, A>) => <B>(data: Task.Result<E, (a: A) => B>) => Task.Result<E, B>;
|
|
1689
|
+
run: (signal?: AbortSignal) => <E, A>(task: Task.Result<E, A>) => Deferred<Result<E, A>>;
|
|
1690
|
+
bindTo: <K extends string>(key: K) => <E, A>(data: Task.Result<E, A>) => Task.Result<E, { [P in K]: A; }>;
|
|
1691
|
+
bind: <K extends string, E, A, B>(key: K, f: (a: A) => Task.Result<E, B>) => (data: Task.Result<E, A>) => Task.Result<E, A & { [P in K]: B; }>;
|
|
1692
|
+
struct: <E, R extends Record<string, any>>(fields: { [K in keyof R]: Task.Result<E, R[K]>; }) => Task.Result<E, R>;
|
|
1693
|
+
retry: (policy: RetryPolicy) => <E, A>(task: Task.Result<E, A>) => Task.Result<E, A>;
|
|
1694
|
+
memoize: <E, A>(task: Task.Result<E, A>) => Task.Result<E, A>;
|
|
1695
|
+
timeout: <E2>(options: {
|
|
1696
|
+
duration: Duration;
|
|
1697
|
+
onTimeout: () => E2;
|
|
1698
|
+
}) => <E1 = never, A = unknown>(task: Task.Result<E1, A>) => Task.Result<E1 | E2, A>;
|
|
1699
|
+
allSettled: <E, A>(tasks: ReadonlyArray<Task.Result<E, A>>) => Task<ReadonlyArray<Result<E, A>>>;
|
|
1700
|
+
};
|
|
1701
|
+
Validation: {
|
|
1702
|
+
make: {
|
|
1703
|
+
passed: <E = never, A = unknown>(value: A) => Task.Validation<E, A>;
|
|
1704
|
+
failed: <E, A = never>(error: E) => Task.Validation<E, A>;
|
|
1705
|
+
failedAll: <E, A = never>(errors: NonEmptyArr<E>) => Task.Validation<E, A>;
|
|
1706
|
+
};
|
|
1707
|
+
from: {
|
|
1708
|
+
Validation: <E, A>(validation: Validation<E, A>) => Task.Validation<E, A>;
|
|
1709
|
+
nullable: <E>(onNull: () => E) => <A>(value: A | null | undefined) => Task.Validation<E, A>;
|
|
1710
|
+
Maybe: <E>(onNone: () => E) => <A>(maybe: Maybe<A>) => Task.Validation<E, A>;
|
|
1711
|
+
Result: <E, A>(result: Result<E, A>) => Task.Validation<E, A>;
|
|
1712
|
+
};
|
|
1713
|
+
to: {
|
|
1714
|
+
Result: <E1, E2, A>(combineErrors: (errors: NonEmptyArr<E1>) => E2) => (data: Task.Validation<E1, A>) => Task.Result<E2, A>;
|
|
1715
|
+
Maybe: <E, A>(data: Task.Validation<E, A>) => Task.Maybe<A>;
|
|
1716
|
+
};
|
|
1717
|
+
tryCatch: <E, A>(f: (signal?: AbortSignal) => Thenable<A>, options: {
|
|
1718
|
+
onError: (error: unknown) => E;
|
|
1719
|
+
}) => Task.Validation<E, A>;
|
|
1720
|
+
map: <E, A, B>(f: (a: A) => B) => (data: Task.Validation<E, A>) => Task.Validation<E, B>;
|
|
1721
|
+
ap: <E, A>(arg: Task.Validation<E, A>) => <B>(data: Task.Validation<E, (a: A) => B>) => Task.Validation<E, B>;
|
|
1722
|
+
fold: <E, A, B>(onFailed: (errors: NonEmptyArr<E>) => B, onPassed: (a: A) => B) => (data: Task.Validation<E, A>) => Task<B>;
|
|
1723
|
+
match: <E, A, B>(cases: {
|
|
1724
|
+
passed: (a: A) => B;
|
|
1725
|
+
failed: (errors: NonEmptyArr<E>) => B;
|
|
1726
|
+
}) => (data: Task.Validation<E, A>) => Task<B>;
|
|
1727
|
+
getOrElse: <B>(defaultValue: () => B) => <E, A>(data: Task.Validation<E, A>) => Task<A | B>;
|
|
1728
|
+
tap: <E, A>(f: (a: A) => void) => (data: Task.Validation<E, A>) => Task.Validation<E, A>;
|
|
1729
|
+
recover: <E, B>(fallback: (errors: NonEmptyArr<E>) => Task.Validation<E, B>) => <A>(data: Task.Validation<E, A>) => Task.Validation<E, A | B>;
|
|
1730
|
+
recoverUnless: <E, B>(isBlocked: (errors: NonEmptyArr<E>) => boolean, fallback: (errors: NonEmptyArr<E>) => Task.Validation<E, B>) => <A>(data: Task.Validation<E, A>) => Task.Validation<E, A | B>;
|
|
1731
|
+
product: <E, A, B>(first: Task.Validation<E, A>, second: Task.Validation<E, B>) => Task.Validation<E, readonly [A, B]>;
|
|
1732
|
+
productAll: <E, A>(data: NonEmptyArr<Task.Validation<E, A>>) => Task.Validation<E, readonly A[]>;
|
|
1733
|
+
mapError: <E, F, A>(f: (e: E) => F) => (data: Task.Validation<E, A>) => Task.Validation<F, A>;
|
|
1734
|
+
tapError: <E, A>(f: (errors: NonEmptyArr<E>) => void) => (data: Task.Validation<E, A>) => Task.Validation<E, A>;
|
|
1735
|
+
struct: <E, R extends Record<string, any>>(fields: { [K in keyof R]: Task.Validation<E, R[K]>; }) => Task.Validation<E, R>;
|
|
1736
|
+
memoize: <E, A>(task: Task.Validation<E, A>) => Task.Validation<E, A>;
|
|
1737
|
+
};
|
|
1738
|
+
};
|
|
1739
|
+
declare namespace Task {
|
|
1740
|
+
type LabeledTask<L extends string, A> = Task<A> & {
|
|
1741
|
+
readonly label: L;
|
|
1742
|
+
};
|
|
1743
|
+
type Maybe<A> = Task<_CoreMaybe<A>>;
|
|
1744
|
+
type Result<E, A> = Task<_CoreResult<E, A>>;
|
|
1745
|
+
type Validation<E, A> = Task<_CoreValidation<E, A>>;
|
|
2451
1746
|
}
|
|
2452
1747
|
|
|
2453
1748
|
export { Equality as E, type Failed as F, Maybe as M, type None as N, type Ok as O, type Passed as P, Result as R, type Some as S, Task as T, Validation as V, type Err as a, Ordering as b };
|