unthrown 3.0.0 → 3.1.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 +5 -2
- package/dist/index.cjs +199 -43
- package/dist/index.d.cts +506 -107
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +506 -107
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +199 -43
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -6
- package/docs/index.md +0 -1407
package/dist/index.d.cts
CHANGED
|
@@ -16,13 +16,37 @@ type Prettify<T> = { [K in keyof T]: T[K] } & {};
|
|
|
16
16
|
*/
|
|
17
17
|
type Bound<T, K extends string, U> = Prettify<Omit<T, K> & { readonly [P in K]: U }>;
|
|
18
18
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
19
|
+
* Compile-time rejection of a thenable callback result — the type-level
|
|
20
|
+
* enforcement of "combinator callbacks are synchronous" (see the
|
|
21
|
+
* {@link AsyncResult} remarks).
|
|
22
|
+
*
|
|
23
|
+
* @remarks
|
|
24
|
+
* Resolves to `unknown` (a no-op in an intersection) for any non-thenable `R`,
|
|
25
|
+
* and to an explanatory string-literal type when `R` is a `PromiseLike` — so an
|
|
26
|
+
* `async` callback fails to compile with the explanation in the error. Without
|
|
27
|
+
* this, `async () => …` would be assignable to `() => void`, and its rejection
|
|
28
|
+
* would escape the pipeline as an unhandled rejection instead of a `Defect`.
|
|
29
|
+
* Lift async work with {@link fromPromise} and compose it with `flatMap`.
|
|
30
|
+
*
|
|
31
|
+
* @typeParam R - the callback's inferred return type.
|
|
32
|
+
* @category Types
|
|
33
|
+
*/
|
|
34
|
+
type NotThenable<R> = [R] extends [PromiseLike<unknown>] ? "unthrown: combinator callbacks are synchronous — lift async work with fromPromise and compose with flatMap" : unknown;
|
|
35
|
+
/**
|
|
36
|
+
* The fluent method surface every {@link Result} variant carries — the
|
|
37
|
+
* combinators (`map`, `flatMap`, `mapErr`, `match`, `unwrap`, …), documented one
|
|
38
|
+
* per entry below. Factored out so the three variants ({@link OkView},
|
|
39
|
+
* {@link ErrView}, {@link DefectView}) can each intersect it; {@link AsyncResult}
|
|
40
|
+
* mirrors this surface with async signatures.
|
|
41
|
+
*
|
|
42
|
+
* @remarks
|
|
43
|
+
* This type exists to **document** the surface and to power narrowing — not to be
|
|
44
|
+
* authored against. You obtain it by holding a `Result` (or `AsyncResult`), never
|
|
45
|
+
* by implementing your own `Result`-like; treat it as read-only reference.
|
|
22
46
|
*
|
|
23
47
|
* @typeParam T - the success value type.
|
|
24
48
|
* @typeParam E - the modeled error type.
|
|
25
|
-
* @
|
|
49
|
+
* @category Methods
|
|
26
50
|
*/
|
|
27
51
|
type ResultMethods<T, E> = {
|
|
28
52
|
/**
|
|
@@ -31,10 +55,12 @@ type ResultMethods<T, E> = {
|
|
|
31
55
|
* Runs `f` only on `Ok`; `Err` and `Defect` pass through untouched. If `f`
|
|
32
56
|
* throws, the thrown value is captured as a `Defect`.
|
|
33
57
|
*
|
|
58
|
+
* An async callback is rejected at compile time ({@link NotThenable}).
|
|
59
|
+
*
|
|
34
60
|
* @typeParam U - the mapped success type.
|
|
35
61
|
* @param f - maps the current success value to a new one.
|
|
36
62
|
*/
|
|
37
|
-
map<U>(f: (value: T) => U): Result$1<U, E>;
|
|
63
|
+
map<U>(f: (value: T) => U & NotThenable<U>): Result$1<U, E>;
|
|
38
64
|
/**
|
|
39
65
|
* Sequence a dependent, `Result`-returning step (monadic bind).
|
|
40
66
|
*
|
|
@@ -50,11 +76,12 @@ type ResultMethods<T, E> = {
|
|
|
50
76
|
* Run a side effect on the success value and pass the `Result` through
|
|
51
77
|
* unchanged.
|
|
52
78
|
*
|
|
53
|
-
* Runs only on `Ok`. If `f` throws, the throw becomes a `Defect`.
|
|
79
|
+
* Runs only on `Ok`. If `f` throws, the throw becomes a `Defect`. An async
|
|
80
|
+
* callback is rejected at compile time ({@link NotThenable}).
|
|
54
81
|
*
|
|
55
82
|
* @param f - the side effect (its return value is ignored).
|
|
56
83
|
*/
|
|
57
|
-
tap(f: (value: T) =>
|
|
84
|
+
tap<R>(f: (value: T) => R & NotThenable<R>): Result$1<T, E>;
|
|
58
85
|
/**
|
|
59
86
|
* Run a **failable** side effect on the success value, keeping the original
|
|
60
87
|
* value but threading the effect's error.
|
|
@@ -99,14 +126,15 @@ type ResultMethods<T, E> = {
|
|
|
99
126
|
* @remarks
|
|
100
127
|
* `f` receives the scope and returns a value (not a `Result`); it is added as
|
|
101
128
|
* `{ ...scope, [name]: value }`. Runs only on `Ok`; `Err`/`Defect` pass
|
|
102
|
-
* through. A throw becomes a `Defect`.
|
|
129
|
+
* through. A throw becomes a `Defect`. An async callback is rejected at
|
|
130
|
+
* compile time ({@link NotThenable}).
|
|
103
131
|
*
|
|
104
132
|
* @typeParam K - the key the value is stored under.
|
|
105
133
|
* @typeParam U - the value type.
|
|
106
134
|
* @param name - the scope key.
|
|
107
135
|
* @param f - computes a value from the accumulated scope.
|
|
108
136
|
*/
|
|
109
|
-
let<K extends string, U>(name: K, f: (scope: T) => U): Result$1<Bound<T, K, U>, E>;
|
|
137
|
+
let<K extends string, U>(name: K, f: (scope: T) => U & NotThenable<U>): Result$1<Bound<T, K, U>, E>;
|
|
110
138
|
/**
|
|
111
139
|
* Replace the success value with a constant `value`.
|
|
112
140
|
*
|
|
@@ -119,12 +147,13 @@ type ResultMethods<T, E> = {
|
|
|
119
147
|
* Transform the modeled error with `f`.
|
|
120
148
|
*
|
|
121
149
|
* Runs `f` only on `Err`; `Ok` passes through and a `Defect` is **never**
|
|
122
|
-
* touched. If `f` throws, the throw becomes a `Defect`.
|
|
150
|
+
* touched. If `f` throws, the throw becomes a `Defect`. An async callback is
|
|
151
|
+
* rejected at compile time ({@link NotThenable}).
|
|
123
152
|
*
|
|
124
153
|
* @typeParam E2 - the mapped error type.
|
|
125
154
|
* @param f - maps the current error to a new one.
|
|
126
155
|
*/
|
|
127
|
-
mapErr<E2>(f: (error: E) => E2): Result$1<T, E2>;
|
|
156
|
+
mapErr<E2>(f: (error: E) => E2 & NotThenable<E2>): Result$1<T, E2>;
|
|
128
157
|
/**
|
|
129
158
|
* Recover from an `Err` by producing another `Result`.
|
|
130
159
|
*
|
|
@@ -144,20 +173,24 @@ type ResultMethods<T, E> = {
|
|
|
144
173
|
* The result type is `Result<T | U, never>`, but `never` describes only the
|
|
145
174
|
* **error** channel — a `Defect` can still be present at runtime, so do not
|
|
146
175
|
* read `never` as "total". Runs `f` only on `Err`; `Ok` and `Defect` pass
|
|
147
|
-
* through. If `f` throws, the throw becomes a `Defect`.
|
|
176
|
+
* through. If `f` throws, the throw becomes a `Defect`. An async callback is
|
|
177
|
+
* rejected at compile time ({@link NotThenable}).
|
|
148
178
|
*
|
|
149
179
|
* @typeParam U - the recovered success type.
|
|
150
180
|
* @param f - produces a success value from the current error.
|
|
151
181
|
*/
|
|
152
|
-
recover<U>(f: (error: E) => U): Result$1<T | U, never>;
|
|
182
|
+
recover<U>(f: (error: E) => U & NotThenable<U>): Result$1<T | U, never>;
|
|
153
183
|
/**
|
|
154
184
|
* Run a side effect on the error and pass the `Result` through unchanged.
|
|
155
185
|
*
|
|
156
|
-
* Runs only on `Err`. If `f` throws, the
|
|
186
|
+
* Runs only on `Err`. If `f` throws, the result is a `Defect` whose cause is
|
|
187
|
+
* an `AggregateError` of `[thrown, original failure]` — observing a failure
|
|
188
|
+
* never destroys it. An async callback is rejected at compile time
|
|
189
|
+
* ({@link NotThenable}).
|
|
157
190
|
*
|
|
158
191
|
* @param f - the side effect (its return value is ignored).
|
|
159
192
|
*/
|
|
160
|
-
tapErr(f: (error: E) =>
|
|
193
|
+
tapErr<R>(f: (error: E) => R & NotThenable<R>): Result$1<T, E>;
|
|
161
194
|
/**
|
|
162
195
|
* Run a **failable** side effect on the error, keeping the original error but
|
|
163
196
|
* threading the effect's own error.
|
|
@@ -167,9 +200,10 @@ type ResultMethods<T, E> = {
|
|
|
167
200
|
* returns a `Result`, but its **success value is discarded** — on the effect's
|
|
168
201
|
* `Ok` the original `Err` flows through unchanged, while an `Err` (or `Defect`)
|
|
169
202
|
* from `f` short-circuits and threads its error (`Result<T, E | E2>`). Runs only
|
|
170
|
-
* on `Err`; `Ok` and `Defect` pass through. If `f` throws, the
|
|
171
|
-
* `Defect
|
|
172
|
-
*
|
|
203
|
+
* on `Err`; `Ok` and `Defect` pass through. If `f` throws, the result is a
|
|
204
|
+
* `Defect` whose cause is an `AggregateError` of `[thrown, original failure]` —
|
|
205
|
+
* observing a failure never destroys it. Use it for a failable effect _during_
|
|
206
|
+
* error handling (e.g. writing the error to an audit log that may itself fail).
|
|
173
207
|
*
|
|
174
208
|
* @typeParam E2 - the error type the effect may introduce.
|
|
175
209
|
* @param f - the failable side effect; its `Ok` value is ignored.
|
|
@@ -191,11 +225,14 @@ type ResultMethods<T, E> = {
|
|
|
191
225
|
recoverDefect<U, E2>(f: (cause: unknown) => Result$1<U, E2>): Result$1<T | U, E | E2>;
|
|
192
226
|
/**
|
|
193
227
|
* Run a side effect on a present `Defect`'s cause (e.g. logging) and pass the
|
|
194
|
-
* `Defect` through unchanged.
|
|
228
|
+
* `Defect` through unchanged. If `f` throws, the result is a `Defect` whose
|
|
229
|
+
* cause is an `AggregateError` of `[thrown, original failure]` — observing a
|
|
230
|
+
* failure never destroys it. An async callback is rejected at compile time
|
|
231
|
+
* ({@link NotThenable}).
|
|
195
232
|
*
|
|
196
233
|
* @param f - the side effect over the unknown cause.
|
|
197
234
|
*/
|
|
198
|
-
tapDefect(f: (cause: unknown) =>
|
|
235
|
+
tapDefect<R>(f: (cause: unknown) => R & NotThenable<R>): Result$1<T, E>;
|
|
199
236
|
/**
|
|
200
237
|
* Exhaustively fold all three runtime states into a single value of type `R`.
|
|
201
238
|
*
|
|
@@ -234,18 +271,20 @@ type ResultMethods<T, E> = {
|
|
|
234
271
|
/**
|
|
235
272
|
* The success value, or `fallback` on `Err`.
|
|
236
273
|
*
|
|
237
|
-
* @
|
|
274
|
+
* @typeParam U - the fallback type (may differ from `T`; the return widens to `T | U`).
|
|
275
|
+
* @param fallback - returned when the result is an `Err` (may be a different type; the return widens to `T | U`).
|
|
238
276
|
* @throws Re-throws on a `Defect` — a Defect is a bug, not an absent value, so
|
|
239
277
|
* it is never silently replaced.
|
|
240
278
|
*/
|
|
241
|
-
unwrapOr(fallback:
|
|
279
|
+
unwrapOr<U>(fallback: U): T | U;
|
|
242
280
|
/**
|
|
243
281
|
* The success value, or `f(error)` on `Err`.
|
|
244
282
|
*
|
|
245
|
-
* @
|
|
283
|
+
* @typeParam U - the fallback type (may differ from `T`; the return widens to `T | U`).
|
|
284
|
+
* @param f - lazily computes the fallback from the error (may return a different type; the return widens to `T | U`).
|
|
246
285
|
* @throws Re-throws on a `Defect`.
|
|
247
286
|
*/
|
|
248
|
-
unwrapOrElse(f: (error: E) =>
|
|
287
|
+
unwrapOrElse<U>(f: (error: E) => U): T | U;
|
|
249
288
|
/**
|
|
250
289
|
* The success value, or `null` on `Err`.
|
|
251
290
|
*
|
|
@@ -263,17 +302,58 @@ type ResultMethods<T, E> = {
|
|
|
263
302
|
isDefect(): this is DefectView<T, E>; /** Lift this synchronous `Result` into an {@link AsyncResult}. */
|
|
264
303
|
toAsync(): AsyncResult$1<T, E>;
|
|
265
304
|
};
|
|
266
|
-
/**
|
|
305
|
+
/**
|
|
306
|
+
* The `Ok` variant of a {@link Result}: a success carrying a `value`. This is
|
|
307
|
+
* what a successful `isOk` guard narrows to, making `.value` reachable. It also
|
|
308
|
+
* carries the shared fluent surface ({@link ResultMethods}).
|
|
309
|
+
*
|
|
310
|
+
* @example
|
|
311
|
+
* ```ts
|
|
312
|
+
* if (r.isOk()) r.value; // r: OkView<T, E> here — .value is a T
|
|
313
|
+
* ```
|
|
314
|
+
*
|
|
315
|
+
* @category Types
|
|
316
|
+
*/
|
|
267
317
|
type OkView<T, E = never> = ResultMethods<T, E> & {
|
|
268
318
|
readonly tag: "Ok";
|
|
269
319
|
readonly value: T;
|
|
270
320
|
};
|
|
271
|
-
/**
|
|
321
|
+
/**
|
|
322
|
+
* The `Err` variant of a {@link Result}: a modeled failure carrying an `error`.
|
|
323
|
+
* This is what a successful `isErr` guard narrows to, exposing `.error`. It also
|
|
324
|
+
* carries the shared fluent surface ({@link ResultMethods}).
|
|
325
|
+
*
|
|
326
|
+
* @remarks
|
|
327
|
+
* **Note the parameter order: `ErrView<E, T>` puts the error type _first_** — the
|
|
328
|
+
* reverse of the `<T, E>` order used by {@link OkView}, {@link DefectView}, and
|
|
329
|
+
* {@link Result} — because `Result<T, E>` narrows to `ErrView<E, T>` (the error is
|
|
330
|
+
* the payload the guard makes reachable). You rarely write it by hand (a failed
|
|
331
|
+
* `isErr()` narrows to it for you); if you do, mind the flip — `ErrView<MyError,
|
|
332
|
+
* MyValue>`, not `ErrView<MyValue, MyError>`.
|
|
333
|
+
*
|
|
334
|
+
* @example
|
|
335
|
+
* ```ts
|
|
336
|
+
* if (r.isErr()) r.error; // r: ErrView<E, T> here — .error is an E
|
|
337
|
+
* ```
|
|
338
|
+
*
|
|
339
|
+
* @category Types
|
|
340
|
+
*/
|
|
272
341
|
type ErrView<E, T = never> = ResultMethods<T, E> & {
|
|
273
342
|
readonly tag: "Err";
|
|
274
343
|
readonly error: E;
|
|
275
344
|
};
|
|
276
|
-
/**
|
|
345
|
+
/**
|
|
346
|
+
* The `Defect` variant of a {@link Result}: an unmodeled failure carrying a
|
|
347
|
+
* `cause`. This is what a successful `isDefect` guard narrows to, exposing
|
|
348
|
+
* `.cause`. It also carries the shared fluent surface ({@link ResultMethods}).
|
|
349
|
+
*
|
|
350
|
+
* @example
|
|
351
|
+
* ```ts
|
|
352
|
+
* if (r.isDefect()) r.cause; // r: DefectView<T, E> here — .cause is `unknown`
|
|
353
|
+
* ```
|
|
354
|
+
*
|
|
355
|
+
* @category Types
|
|
356
|
+
*/
|
|
277
357
|
type DefectView<T = never, E = never> = ResultMethods<T, E> & {
|
|
278
358
|
readonly tag: "Defect";
|
|
279
359
|
readonly cause: unknown;
|
|
@@ -324,107 +404,227 @@ type Result$1<T, E> = OkView<T, E> | ErrView<E, T> | DefectView<T, E>;
|
|
|
324
404
|
* An {@link AsyncResult}'s internal promise never rejects, so `await`-ing one
|
|
325
405
|
* always yields a {@link Result} and never throws — there is no rejection
|
|
326
406
|
* channel to model, and none is advertised. At runtime it is still a thenable
|
|
327
|
-
* (the only way `await` can collapse it)
|
|
328
|
-
*
|
|
407
|
+
* (the only way `await` can collapse it), and `Promise.all` / `Promise.resolve`
|
|
408
|
+
* will still adopt it — harmlessly, since it settles to a `Result` and never
|
|
409
|
+
* rejects. What the narrowing prevents is treating it as a full promise:
|
|
410
|
+
* `.catch()` / `.finally()` do not type-check, because there is no rejection to
|
|
411
|
+
* handle.
|
|
329
412
|
*
|
|
330
413
|
* @typeParam T - the value `await` resolves to.
|
|
414
|
+
*
|
|
415
|
+
* @category Types
|
|
331
416
|
*/
|
|
332
417
|
type Awaitable<T> = {
|
|
333
418
|
then<R = T>(onfulfilled?: ((value: T) => R | PromiseLike<R>) | null): PromiseLike<R>;
|
|
334
419
|
};
|
|
335
420
|
/**
|
|
336
|
-
* The
|
|
337
|
-
*
|
|
421
|
+
* The async method surface every {@link AsyncResult} carries — the combinators
|
|
422
|
+
* (`map`, `flatMap`, `mapErr`, `match`, `unwrap`, …) with their asynchronous
|
|
423
|
+
* signatures, documented one per entry below. The async mirror of
|
|
424
|
+
* {@link ResultMethods}: each entry links its synchronous counterpart and states
|
|
425
|
+
* only the async delta.
|
|
338
426
|
*
|
|
339
427
|
* @remarks
|
|
340
|
-
*
|
|
341
|
-
*
|
|
342
|
-
*
|
|
343
|
-
* {@link
|
|
344
|
-
*
|
|
345
|
-
*
|
|
346
|
-
*
|
|
347
|
-
* `AsyncResult`.
|
|
348
|
-
*
|
|
349
|
-
* To pattern-match an `AsyncResult`, `await` it first: `match(await ar)`.
|
|
428
|
+
* Like {@link ResultMethods}, this type exists to **document** the surface — not
|
|
429
|
+
* to be authored against; you obtain it by holding an `AsyncResult`. Its
|
|
430
|
+
* combinator callbacks are **synchronous** (a raw `Promise` may never enter — see
|
|
431
|
+
* the {@link AsyncResult} remarks); async work re-enters via {@link fromPromise}
|
|
432
|
+
* and composes with `flatMap`. Systematic differences from the sync surface: the
|
|
433
|
+
* binds return an `AsyncResult` (and additionally accept one), and the
|
|
434
|
+
* eliminators return a `Promise`.
|
|
350
435
|
*
|
|
351
436
|
* @typeParam T - the success value type.
|
|
352
437
|
* @typeParam E - the modeled error type.
|
|
438
|
+
* @category Methods
|
|
353
439
|
*/
|
|
354
|
-
type
|
|
355
|
-
/** Asynchronous `map`. `f` is synchronous; a throw becomes a `Defect`. */map<U>(f: (value: T) => U): AsyncResult$1<U, E>;
|
|
440
|
+
type AsyncResultMethods<T, E> = {
|
|
356
441
|
/**
|
|
357
|
-
* Asynchronous
|
|
358
|
-
*
|
|
442
|
+
* Asynchronous {@link ResultMethods.map | map}: transforms the success value
|
|
443
|
+
* with `f`. `f` is synchronous; a throw becomes a `Defect`. An async callback
|
|
444
|
+
* is rejected at compile time ({@link NotThenable}).
|
|
359
445
|
*/
|
|
360
|
-
|
|
361
|
-
tap(f: (value: T) => void): AsyncResult$1<T, E>;
|
|
446
|
+
map<U>(f: (value: T) => U & NotThenable<U>): AsyncResult$1<U, E>;
|
|
362
447
|
/**
|
|
363
|
-
* Asynchronous
|
|
364
|
-
* may return a `Result` **or** an `AsyncResult
|
|
365
|
-
*
|
|
448
|
+
* Asynchronous {@link ResultMethods.flatMap | flatMap}. Unlike the sync form,
|
|
449
|
+
* `f` may return a `Result` **or** an `AsyncResult` (never a raw `Promise`); a
|
|
450
|
+
* throw becomes a `Defect`.
|
|
366
451
|
*/
|
|
367
|
-
|
|
452
|
+
flatMap<U, E2>(f: (value: T) => Result$1<U, E2> | AsyncResult$1<U, E2>): AsyncResult$1<U, E | E2>;
|
|
368
453
|
/**
|
|
369
|
-
* Asynchronous
|
|
370
|
-
*
|
|
454
|
+
* Asynchronous {@link ResultMethods.tap | tap}. `f` is synchronous; a throw
|
|
455
|
+
* becomes a `Defect`. An async callback is rejected at compile time
|
|
456
|
+
* ({@link NotThenable}).
|
|
371
457
|
*/
|
|
372
|
-
|
|
373
|
-
let<K extends string, U>(name: K, f: (scope: T) => U): AsyncResult$1<Bound<T, K, U>, E>; /** Asynchronous `as`. */
|
|
374
|
-
as<U>(value: U): AsyncResult$1<U, E>; /** Asynchronous `mapErr`. `f` is synchronous; a throw becomes a `Defect`. */
|
|
375
|
-
mapErr<E2>(f: (error: E) => E2): AsyncResult$1<T, E2>; /** Asynchronous `orElse`. `f` may return a `Result` or an `AsyncResult`. */
|
|
376
|
-
orElse<U, E2>(f: (error: E) => Result$1<U, E2> | AsyncResult$1<U, E2>): AsyncResult$1<T | U, E2>; /** Asynchronous `recover`. `f` is synchronous; a throw becomes a `Defect`. */
|
|
377
|
-
recover<U>(f: (error: E) => U): AsyncResult$1<T | U, never>; /** Asynchronous `tapErr`. `f` is synchronous; a throw becomes a `Defect`. */
|
|
378
|
-
tapErr(f: (error: E) => void): AsyncResult$1<T, E>;
|
|
458
|
+
tap<R>(f: (value: T) => R & NotThenable<R>): AsyncResult$1<T, E>;
|
|
379
459
|
/**
|
|
380
|
-
* Asynchronous
|
|
381
|
-
* original
|
|
382
|
-
* value is discarded, an `Err`/`Defect`
|
|
460
|
+
* Asynchronous {@link ResultMethods.flatTap | flatTap} — a failable tap that
|
|
461
|
+
* keeps the original value. `f` may return a `Result` **or** an `AsyncResult`;
|
|
462
|
+
* its `Ok` value is discarded, an `Err`/`Defect` short-circuits, and a throw
|
|
383
463
|
* becomes a `Defect`.
|
|
384
464
|
*/
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
465
|
+
flatTap<E2>(f: (value: T) => Result$1<unknown, E2> | AsyncResult$1<unknown, E2>): AsyncResult$1<T, E | E2>;
|
|
466
|
+
/**
|
|
467
|
+
* Asynchronous {@link ResultMethods.bind | bind} (do-notation). `f` may return
|
|
468
|
+
* a `Result` **or** an `AsyncResult`; its value is bound under `name` in the
|
|
469
|
+
* accumulating scope.
|
|
470
|
+
*/
|
|
471
|
+
bind<K extends string, U, E2>(name: K, f: (scope: T) => Result$1<U, E2> | AsyncResult$1<U, E2>): AsyncResult$1<Bound<T, K, U>, E | E2>;
|
|
472
|
+
/**
|
|
473
|
+
* Asynchronous {@link ResultMethods.let | let} (do-notation). `f` returns a
|
|
474
|
+
* plain value, bound under `name`. An async callback is rejected at compile
|
|
475
|
+
* time ({@link NotThenable}).
|
|
476
|
+
*/
|
|
477
|
+
let<K extends string, U>(name: K, f: (scope: T) => U & NotThenable<U>): AsyncResult$1<Bound<T, K, U>, E>; /** Asynchronous {@link ResultMethods.as | as}: replaces the value with `value`. */
|
|
478
|
+
as<U>(value: U): AsyncResult$1<U, E>;
|
|
479
|
+
/**
|
|
480
|
+
* Asynchronous {@link ResultMethods.mapErr | mapErr}. `f` is synchronous; a
|
|
481
|
+
* throw becomes a `Defect`. An async callback is rejected at compile time
|
|
482
|
+
* ({@link NotThenable}).
|
|
483
|
+
*/
|
|
484
|
+
mapErr<E2>(f: (error: E) => E2 & NotThenable<E2>): AsyncResult$1<T, E2>;
|
|
485
|
+
/**
|
|
486
|
+
* Asynchronous {@link ResultMethods.orElse | orElse}. `f` may return a `Result`
|
|
487
|
+
* or an `AsyncResult`.
|
|
488
|
+
*/
|
|
489
|
+
orElse<U, E2>(f: (error: E) => Result$1<U, E2> | AsyncResult$1<U, E2>): AsyncResult$1<T | U, E2>;
|
|
490
|
+
/**
|
|
491
|
+
* Asynchronous {@link ResultMethods.recover | recover}. `f` is synchronous; a
|
|
492
|
+
* throw becomes a `Defect`. An async callback is rejected at compile time
|
|
493
|
+
* ({@link NotThenable}).
|
|
494
|
+
*/
|
|
495
|
+
recover<U>(f: (error: E) => U & NotThenable<U>): AsyncResult$1<T | U, never>;
|
|
496
|
+
/**
|
|
497
|
+
* Asynchronous {@link ResultMethods.tapErr | tapErr}. `f` is synchronous; if it
|
|
498
|
+
* throws, the result is a `Defect` whose cause is an `AggregateError` of
|
|
499
|
+
* `[thrown, original failure]` — observing a failure never destroys it. An
|
|
500
|
+
* async callback is rejected at compile time ({@link NotThenable}).
|
|
501
|
+
*/
|
|
502
|
+
tapErr<R>(f: (error: E) => R & NotThenable<R>): AsyncResult$1<T, E>;
|
|
503
|
+
/**
|
|
504
|
+
* Asynchronous {@link ResultMethods.flatTapErr | flatTapErr} — the
|
|
505
|
+
* error-channel mirror of `flatTap`. `f` may return a `Result` **or** an
|
|
506
|
+
* `AsyncResult`; its `Ok` value is discarded, an `Err`/`Defect` from `f`
|
|
507
|
+
* threads through, and if `f` throws, the result is a `Defect` whose cause is
|
|
508
|
+
* an `AggregateError` of `[thrown, original failure]` — observing a failure
|
|
509
|
+
* never destroys it.
|
|
510
|
+
*/
|
|
511
|
+
flatTapErr<E2>(f: (error: E) => Result$1<unknown, E2> | AsyncResult$1<unknown, E2>): AsyncResult$1<T, E | E2>;
|
|
512
|
+
/**
|
|
513
|
+
* Asynchronous {@link ResultMethods.recoverDefect | recoverDefect}. `f` may
|
|
514
|
+
* return a `Result` or an `AsyncResult`.
|
|
515
|
+
*/
|
|
516
|
+
recoverDefect<U, E2>(f: (cause: unknown) => Result$1<U, E2> | AsyncResult$1<U, E2>): AsyncResult$1<T | U, E | E2>;
|
|
517
|
+
/**
|
|
518
|
+
* Asynchronous {@link ResultMethods.tapDefect | tapDefect}. If `f` throws, the
|
|
519
|
+
* result is a `Defect` whose cause is an `AggregateError` of `[thrown,
|
|
520
|
+
* original failure]` — observing a failure never destroys it. An async
|
|
521
|
+
* callback is rejected at compile time ({@link NotThenable}).
|
|
522
|
+
*/
|
|
523
|
+
tapDefect<R>(f: (cause: unknown) => R & NotThenable<R>): AsyncResult$1<T, E>;
|
|
524
|
+
/**
|
|
525
|
+
* Asynchronous {@link ResultMethods.match | match}. Handlers are synchronous;
|
|
526
|
+
* resolves to a `Promise<R>`.
|
|
527
|
+
*/
|
|
388
528
|
match<R>(cases: {
|
|
389
529
|
ok: (value: T) => R;
|
|
390
530
|
err: (error: E) => R;
|
|
391
531
|
defect: (cause: unknown) => R;
|
|
392
|
-
}): Promise<R>;
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
532
|
+
}): Promise<R>;
|
|
533
|
+
/**
|
|
534
|
+
* Asynchronous {@link ResultMethods.unwrap | unwrap}. The returned promise
|
|
535
|
+
* rejects on `Err`/`Defect`.
|
|
536
|
+
*/
|
|
537
|
+
unwrap(): Promise<T>; /** Asynchronous {@link ResultMethods.unwrapErr | unwrapErr}. */
|
|
538
|
+
unwrapErr(): Promise<E>; /** Asynchronous {@link ResultMethods.unwrapOr | unwrapOr}. */
|
|
539
|
+
unwrapOr<U>(fallback: U): Promise<T | U>; /** Asynchronous {@link ResultMethods.unwrapOrElse | unwrapOrElse}. */
|
|
540
|
+
unwrapOrElse<U>(f: (error: E) => U): Promise<T | U>; /** Asynchronous {@link ResultMethods.getOrNull | getOrNull}. */
|
|
541
|
+
getOrNull(): Promise<T | null>; /** Asynchronous {@link ResultMethods.getOrUndefined | getOrUndefined}. */
|
|
398
542
|
getOrUndefined(): Promise<T | undefined>;
|
|
399
543
|
};
|
|
400
544
|
/**
|
|
401
|
-
*
|
|
545
|
+
* The asynchronous counterpart of {@link Result}: an awaitable wrapper carrying
|
|
546
|
+
* the {@link AsyncResultMethods} surface, collapsing to a `Result<T, E>` when
|
|
547
|
+
* `await`-ed.
|
|
548
|
+
*
|
|
549
|
+
* @remarks
|
|
550
|
+
* **Combinator callbacks are synchronous.** A raw `Promise` may never enter an
|
|
551
|
+
* `AsyncResult` method — that would be an un-qualified async boundary, and its
|
|
552
|
+
* rejection would silently become a `Defect`, skipping the triage that
|
|
553
|
+
* {@link fromPromise} forces. To do further async work, re-enter through a
|
|
554
|
+
* qualified boundary and compose it: `ar.flatMap((v) => fromPromise(work(v),
|
|
555
|
+
* qualify))`. The eliminators (`unwrap`, …) return promises; the binds
|
|
556
|
+
* (`flatMap`, `flatTap`, `orElse`, `recoverDefect`) additionally accept an
|
|
557
|
+
* `AsyncResult`. Its combinators are documented one per entry on
|
|
558
|
+
* {@link AsyncResultMethods}.
|
|
559
|
+
*
|
|
560
|
+
* To pattern-match an `AsyncResult`, `await` it first: `match(await ar)`.
|
|
561
|
+
*
|
|
562
|
+
* @typeParam T - the success value type.
|
|
563
|
+
* @typeParam E - the modeled error type.
|
|
564
|
+
*/
|
|
565
|
+
type AsyncResult$1<T, E> = Awaitable<Result$1<T, E>> & AsyncResultMethods<T, E>;
|
|
566
|
+
/**
|
|
567
|
+
* Extract the success type `T` from a `Result` type — derive one type from
|
|
568
|
+
* another instead of restating it (e.g. the payload a function returns).
|
|
402
569
|
*
|
|
403
570
|
* @typeParam R - the `Result` type to inspect.
|
|
571
|
+
*
|
|
572
|
+
* @example
|
|
573
|
+
* ```ts
|
|
574
|
+
* type R = Result<User, NotFound>;
|
|
575
|
+
* type U = OkOf<R>; // User
|
|
576
|
+
* type E = ErrOf<R>; // NotFound
|
|
577
|
+
* ```
|
|
578
|
+
*
|
|
579
|
+
* @category Types
|
|
404
580
|
*/
|
|
405
581
|
type OkOf<R> = R extends {
|
|
406
582
|
readonly tag: "Ok";
|
|
407
583
|
readonly value: infer T;
|
|
408
584
|
} ? T : never;
|
|
409
585
|
/**
|
|
410
|
-
* Extract the error type `E` from a `Result
|
|
586
|
+
* Extract the error type `E` from a `Result` type — the counterpart of
|
|
587
|
+
* {@link OkOf}.
|
|
411
588
|
*
|
|
412
589
|
* @typeParam R - the `Result` type to inspect.
|
|
590
|
+
*
|
|
591
|
+
* @example
|
|
592
|
+
* ```ts
|
|
593
|
+
* type E = ErrOf<Result<User, NotFound>>; // NotFound
|
|
594
|
+
* ```
|
|
595
|
+
*
|
|
596
|
+
* @category Types
|
|
413
597
|
*/
|
|
414
598
|
type ErrOf<R> = R extends {
|
|
415
599
|
readonly tag: "Err";
|
|
416
600
|
readonly error: infer E;
|
|
417
601
|
} ? E : never;
|
|
418
602
|
/**
|
|
419
|
-
* Extract the success type `T` from an {@link AsyncResult}
|
|
603
|
+
* Extract the success type `T` from an {@link AsyncResult} type — the async
|
|
604
|
+
* counterpart of {@link OkOf}.
|
|
420
605
|
*
|
|
421
606
|
* @typeParam R - the `AsyncResult` type to inspect.
|
|
607
|
+
*
|
|
608
|
+
* @example
|
|
609
|
+
* ```ts
|
|
610
|
+
* type T = AsyncOkOf<AsyncResult<User, NotFound>>; // User
|
|
611
|
+
* ```
|
|
612
|
+
*
|
|
613
|
+
* @category Types
|
|
422
614
|
*/
|
|
423
615
|
type AsyncOkOf<R> = R extends AsyncResult$1<infer T, unknown> ? T : never;
|
|
424
616
|
/**
|
|
425
|
-
* Extract the error type `E` from an {@link AsyncResult}
|
|
617
|
+
* Extract the error type `E` from an {@link AsyncResult} type — the async
|
|
618
|
+
* counterpart of {@link ErrOf}.
|
|
426
619
|
*
|
|
427
620
|
* @typeParam R - the `AsyncResult` type to inspect.
|
|
621
|
+
*
|
|
622
|
+
* @example
|
|
623
|
+
* ```ts
|
|
624
|
+
* type E = AsyncErrOf<AsyncResult<User, NotFound>>; // NotFound
|
|
625
|
+
* ```
|
|
626
|
+
*
|
|
627
|
+
* @category Types
|
|
428
628
|
*/
|
|
429
629
|
type AsyncErrOf<R> = R extends AsyncResult$1<unknown, infer E> ? E : never;
|
|
430
630
|
//#endregion
|
|
@@ -438,8 +638,12 @@ type AsyncErrOf<R> = R extends AsyncResult$1<unknown, infer E> ? E : never;
|
|
|
438
638
|
* @example
|
|
439
639
|
* ```ts
|
|
440
640
|
* import { Ok } from "unthrown";
|
|
441
|
-
*
|
|
641
|
+
*
|
|
642
|
+
* Ok(2).map((n) => n + 1); // => Ok(3)
|
|
643
|
+
* Ok(42).unwrap(); // => 42
|
|
442
644
|
* ```
|
|
645
|
+
*
|
|
646
|
+
* @category Constructors
|
|
443
647
|
*/
|
|
444
648
|
declare function Ok<T>(value: T): Result$1<T, never>;
|
|
445
649
|
/**
|
|
@@ -451,8 +655,12 @@ declare function Ok<T>(value: T): Result$1<T, never>;
|
|
|
451
655
|
* @example
|
|
452
656
|
* ```ts
|
|
453
657
|
* import { Err } from "unthrown";
|
|
454
|
-
*
|
|
658
|
+
*
|
|
659
|
+
* Err("not_found").map((n) => n + 1); // => Err("not_found") (map skipped)
|
|
660
|
+
* Err("not_found").unwrapErr(); // => "not_found"
|
|
455
661
|
* ```
|
|
662
|
+
*
|
|
663
|
+
* @category Constructors
|
|
456
664
|
*/
|
|
457
665
|
declare function Err<E>(error: E): Result$1<never, E>;
|
|
458
666
|
/**
|
|
@@ -462,22 +670,61 @@ declare function Err<E>(error: E): Result$1<never, E>;
|
|
|
462
670
|
*
|
|
463
671
|
* @example
|
|
464
672
|
* ```ts
|
|
465
|
-
* import { isOk, type Result } from "unthrown";
|
|
673
|
+
* import { isOk, Ok, Err, type Result } from "unthrown";
|
|
674
|
+
*
|
|
675
|
+
* isOk(Ok(1)); // => true
|
|
676
|
+
* isOk(Err("boom")); // => false
|
|
677
|
+
*
|
|
466
678
|
* declare const r: Result<number, string>;
|
|
467
679
|
* if (isOk(r)) r.value; // number, narrowed
|
|
468
680
|
* ```
|
|
681
|
+
*
|
|
682
|
+
* @category Guards
|
|
469
683
|
*/
|
|
470
684
|
declare function isOk<T, E>(r: Result$1<T, E>): r is OkView<T, E>;
|
|
471
685
|
/**
|
|
472
686
|
* Type guard: narrow a {@link Result} to its `Err` variant, exposing `.error`.
|
|
473
687
|
*
|
|
474
688
|
* @returns `true` when `r` is `Err`.
|
|
689
|
+
*
|
|
690
|
+
* @example
|
|
691
|
+
* ```ts
|
|
692
|
+
* import { isErr, Ok, Err, type Result } from "unthrown";
|
|
693
|
+
*
|
|
694
|
+
* isErr(Err("boom")); // => true
|
|
695
|
+
* isErr(Ok(1)); // => false
|
|
696
|
+
*
|
|
697
|
+
* declare const r: Result<number, string>;
|
|
698
|
+
* if (isErr(r)) r.error; // string, narrowed
|
|
699
|
+
* ```
|
|
700
|
+
*
|
|
701
|
+
* @category Guards
|
|
475
702
|
*/
|
|
476
703
|
declare function isErr<T, E>(r: Result$1<T, E>): r is ErrView<E, T>;
|
|
477
704
|
/**
|
|
478
705
|
* Type guard: narrow a {@link Result} to its `Defect` variant, exposing `.cause`.
|
|
479
706
|
*
|
|
707
|
+
* @remarks
|
|
708
|
+
* A `Defect` has no public constructor — it only arises at a boundary (e.g. a
|
|
709
|
+
* callback throwing inside a combinator). This guard is how you detect one.
|
|
710
|
+
*
|
|
480
711
|
* @returns `true` when `r` is a `Defect`.
|
|
712
|
+
*
|
|
713
|
+
* @example
|
|
714
|
+
* ```ts
|
|
715
|
+
* import { isDefect, Ok } from "unthrown";
|
|
716
|
+
*
|
|
717
|
+
* // A throw inside a combinator is captured as a Defect:
|
|
718
|
+
* const r = Ok(1).map(() => {
|
|
719
|
+
* throw new Error("boom");
|
|
720
|
+
* });
|
|
721
|
+
* isDefect(r); // => true
|
|
722
|
+
* isDefect(Ok(1)); // => false
|
|
723
|
+
*
|
|
724
|
+
* if (isDefect(r)) r.cause; // unknown, narrowed
|
|
725
|
+
* ```
|
|
726
|
+
*
|
|
727
|
+
* @category Guards
|
|
481
728
|
*/
|
|
482
729
|
declare function isDefect<T, E>(r: Result$1<T, E>): r is DefectView<T, E>;
|
|
483
730
|
//#endregion
|
|
@@ -497,6 +744,8 @@ declare function isDefect<T, E>(r: Result$1<T, E>): r is DefectView<T, E>;
|
|
|
497
744
|
* re-thrown (with its original stack) instead.
|
|
498
745
|
*
|
|
499
746
|
* @typeParam E - the type of the {@link UnwrapError.error} it carries.
|
|
747
|
+
*
|
|
748
|
+
* @category Errors
|
|
500
749
|
*/
|
|
501
750
|
declare class UnwrapError<E = unknown> extends Error {
|
|
502
751
|
/**
|
|
@@ -517,6 +766,20 @@ declare class UnwrapError<E = unknown> extends Error {
|
|
|
517
766
|
* is not a `Result` and returns `false`.
|
|
518
767
|
*
|
|
519
768
|
* @returns `true` when `x` is a `Result` produced by this library.
|
|
769
|
+
*
|
|
770
|
+
* @example
|
|
771
|
+
* ```ts
|
|
772
|
+
* import { isResult, Ok } from "unthrown";
|
|
773
|
+
*
|
|
774
|
+
* isResult(Ok(1)); // => true
|
|
775
|
+
* isResult({ tag: "Ok" }); // => false (look-alike, wrong prototype)
|
|
776
|
+
* isResult(Ok(1).toAsync()); // => false (an AsyncResult is not a Result)
|
|
777
|
+
*
|
|
778
|
+
* const x: unknown = Ok(1);
|
|
779
|
+
* if (isResult(x)) x.match({ ok: () => 1, err: () => 0, defect: () => -1 });
|
|
780
|
+
* ```
|
|
781
|
+
*
|
|
782
|
+
* @category Guards
|
|
520
783
|
*/
|
|
521
784
|
declare function isResult(x: unknown): x is Result$1<unknown, unknown>;
|
|
522
785
|
//#endregion
|
|
@@ -542,6 +805,24 @@ declare function isResult(x: unknown): x is Result$1<unknown, unknown>;
|
|
|
542
805
|
* .map(({ user, org, label }) => render(user, org, label));
|
|
543
806
|
* // Result<View, NotFound>
|
|
544
807
|
* ```
|
|
808
|
+
*
|
|
809
|
+
* @example
|
|
810
|
+
* ```ts
|
|
811
|
+
* import { Do, Ok, Err } from "unthrown";
|
|
812
|
+
*
|
|
813
|
+
* // Ok path — the scope accumulates:
|
|
814
|
+
* Do()
|
|
815
|
+
* .bind("a", () => Ok(2))
|
|
816
|
+
* .let("b", ({ a }) => a * 10)
|
|
817
|
+
* .map(({ a, b }) => a + b); // => Ok(22)
|
|
818
|
+
*
|
|
819
|
+
* // Err path — the first Err short-circuits the rest:
|
|
820
|
+
* Do()
|
|
821
|
+
* .bind("a", () => Err("boom"))
|
|
822
|
+
* .let("b", ({ a }) => a); // => Err("boom")
|
|
823
|
+
* ```
|
|
824
|
+
*
|
|
825
|
+
* @category Do-notation
|
|
545
826
|
*/
|
|
546
827
|
declare function Do(): Result$1<{}, never>;
|
|
547
828
|
//#endregion
|
|
@@ -580,10 +861,16 @@ type Defect = {
|
|
|
580
861
|
* @param value - the possibly-absent value.
|
|
581
862
|
* @param onAbsent - lazily produces the error for the absent case.
|
|
582
863
|
*
|
|
864
|
+
* @category Interop
|
|
865
|
+
*
|
|
583
866
|
* @example
|
|
584
867
|
* ```ts
|
|
585
868
|
* import { fromNullable } from "unthrown";
|
|
586
|
-
*
|
|
869
|
+
*
|
|
870
|
+
* const map = new Map([["a", 1]]);
|
|
871
|
+
* fromNullable(map.get("a"), () => "absent").unwrap(); // => 1
|
|
872
|
+
* fromNullable(map.get("z"), () => "absent"); // => Err("absent")
|
|
873
|
+
* fromNullable(0, () => "absent").unwrap(); // => 0 (falsy but present)
|
|
587
874
|
* ```
|
|
588
875
|
*/
|
|
589
876
|
declare function fromNullable<T, E>(value: T | null | undefined, onAbsent: () => E): Result$1<NonNullable<T>, E>;
|
|
@@ -612,11 +899,21 @@ declare function fromNullable<T, E>(value: T | null | undefined, onAbsent: () =>
|
|
|
612
899
|
* unmodeled by returning `defect(cause)` (the helper passed as its second arg).
|
|
613
900
|
* @returns a function with the same arguments returning `Result<T, E>`.
|
|
614
901
|
*
|
|
902
|
+
* @category Interop
|
|
903
|
+
*
|
|
615
904
|
* @example
|
|
616
905
|
* ```ts
|
|
617
906
|
* import { fromThrowable } from "unthrown";
|
|
618
|
-
*
|
|
619
|
-
* parse
|
|
907
|
+
*
|
|
908
|
+
* // Model the parse failure as an `Err`, everything unexpected as a `Defect`.
|
|
909
|
+
* const parse = fromThrowable(
|
|
910
|
+
* (text: string) => JSON.parse(text) as unknown,
|
|
911
|
+
* (cause, defect) =>
|
|
912
|
+
* cause instanceof SyntaxError ? ("invalid_json" as const) : defect(cause),
|
|
913
|
+
* );
|
|
914
|
+
*
|
|
915
|
+
* parse('{"ok":true}').unwrap(); // => { ok: true }
|
|
916
|
+
* parse("nope"); // => Err("invalid_json")
|
|
620
917
|
* ```
|
|
621
918
|
*/
|
|
622
919
|
declare function fromThrowable<A extends unknown[], T, R>(fn: (...args: A) => T, qualify: (cause: unknown, defect: (cause: unknown) => Defect) => R): (...args: A) => Result$1<T, Exclude<R, Defect>>;
|
|
@@ -642,12 +939,19 @@ declare function fromThrowable<A extends unknown[], T, R>(fn: (...args: A) => T,
|
|
|
642
939
|
* @param qualify - triages a rejection `cause` into a modeled `E`, or marks it
|
|
643
940
|
* unmodeled by returning `defect(cause)` (the helper passed as its second arg).
|
|
644
941
|
*
|
|
942
|
+
* @category Interop
|
|
943
|
+
*
|
|
645
944
|
* @example
|
|
646
945
|
* ```ts
|
|
647
946
|
* import { fromPromise } from "unthrown";
|
|
947
|
+
*
|
|
948
|
+
* // A rejection with a NotFoundError becomes a modeled `Err`; anything else a Defect.
|
|
648
949
|
* const user = await fromPromise(fetchUser(id), (cause, defect) =>
|
|
649
950
|
* cause instanceof NotFoundError ? ("not_found" as const) : defect(cause),
|
|
650
951
|
* );
|
|
952
|
+
*
|
|
953
|
+
* user.unwrap(); // => the fetched user (on success)
|
|
954
|
+
* // when fetchUser rejects with NotFoundError: => Err("not_found")
|
|
651
955
|
* ```
|
|
652
956
|
*/
|
|
653
957
|
declare function fromPromise<T, R>(promise: Promise<T> | (() => Promise<T>), qualify: (cause: unknown, defect: (cause: unknown) => Defect) => R): AsyncResult$1<T, Exclude<R, Defect>>;
|
|
@@ -662,6 +966,17 @@ declare function fromPromise<T, R>(promise: Promise<T> | (() => Promise<T>), qua
|
|
|
662
966
|
*
|
|
663
967
|
* @typeParam T - the resolved value type.
|
|
664
968
|
* @param promise - the promise, or a thunk returning one.
|
|
969
|
+
*
|
|
970
|
+
* @category Interop
|
|
971
|
+
*
|
|
972
|
+
* @example
|
|
973
|
+
* ```ts
|
|
974
|
+
* import { fromSafePromise } from "unthrown";
|
|
975
|
+
*
|
|
976
|
+
* (await fromSafePromise(Promise.resolve(3))).unwrap(); // => 3
|
|
977
|
+
* // a rejection becomes a Defect (never a modeled Err):
|
|
978
|
+
* await fromSafePromise(Promise.reject(new Error("boom"))); // => Defect(Error("boom"))
|
|
979
|
+
* ```
|
|
665
980
|
*/
|
|
666
981
|
declare function fromSafePromise<T>(promise: Promise<T> | (() => Promise<T>)): AsyncResult$1<T, never>;
|
|
667
982
|
/**
|
|
@@ -698,11 +1013,14 @@ type AsyncResultRecord = Record<string, AsyncResult$1<unknown, unknown>>;
|
|
|
698
1013
|
* collapses to `Result<T[], E>` with no cast. For a **record** keyed by name,
|
|
699
1014
|
* use {@link allFromDict}.
|
|
700
1015
|
*
|
|
1016
|
+
* @category Aggregate
|
|
1017
|
+
*
|
|
701
1018
|
* @example
|
|
702
1019
|
* ```ts
|
|
703
|
-
* import { all, Ok } from "unthrown";
|
|
704
|
-
*
|
|
705
|
-
* all([Ok(1), Ok(
|
|
1020
|
+
* import { all, Ok, Err } from "unthrown";
|
|
1021
|
+
*
|
|
1022
|
+
* all([Ok(1), Ok("a"), Ok(true)]).unwrap(); // => [1, "a", true] (typed [number, string, boolean])
|
|
1023
|
+
* all([Ok(1), Err("e"), Ok(3)]); // => Err("e") (short-circuits on the first Err)
|
|
706
1024
|
* ```
|
|
707
1025
|
*/
|
|
708
1026
|
declare function all<Rs extends readonly Result$1<unknown, unknown>[]>(results: readonly [...Rs]): Result$1<AllOk<Rs, { [K in keyof Rs]: OkOf<Rs[K]> }>, ErrOf<Rs[number]>>;
|
|
@@ -716,10 +1034,14 @@ declare function all<Rs extends readonly Result$1<unknown, unknown>[]>(results:
|
|
|
716
1034
|
* Same folding rules as {@link all}: first `Err` short-circuits, any `Defect`
|
|
717
1035
|
* dominates. This is **not** error accumulation.
|
|
718
1036
|
*
|
|
1037
|
+
* @category Aggregate
|
|
1038
|
+
*
|
|
719
1039
|
* @example
|
|
720
1040
|
* ```ts
|
|
721
|
-
* import { allFromDict, Ok } from "unthrown";
|
|
722
|
-
*
|
|
1041
|
+
* import { allFromDict, Ok, Err } from "unthrown";
|
|
1042
|
+
*
|
|
1043
|
+
* allFromDict({ id: Ok(1), name: Ok("ada") }).unwrap(); // => { id: 1, name: "ada" }
|
|
1044
|
+
* allFromDict({ id: Ok(1), name: Err("missing") }); // => Err("missing")
|
|
723
1045
|
* ```
|
|
724
1046
|
*/
|
|
725
1047
|
declare function allFromDict<R extends ResultRecord>(results: R): Result$1<{ [K in keyof R]: OkOf<R[K]> }, ErrOf<R[keyof R]>>;
|
|
@@ -733,10 +1055,14 @@ declare function allFromDict<R extends ResultRecord>(results: R): Result$1<{ [K
|
|
|
733
1055
|
* short-circuits, any `Defect` dominates. As ever, the returned `AsyncResult`'s
|
|
734
1056
|
* internal promise never rejects. For a **record**, use {@link allFromDictAsync}.
|
|
735
1057
|
*
|
|
1058
|
+
* @category Aggregate
|
|
1059
|
+
*
|
|
736
1060
|
* @example
|
|
737
1061
|
* ```ts
|
|
738
1062
|
* import { allAsync, fromSafePromise } from "unthrown";
|
|
739
|
-
*
|
|
1063
|
+
*
|
|
1064
|
+
* const both = allAsync([fromSafePromise(Promise.resolve(1)), fromSafePromise(Promise.resolve(2))]);
|
|
1065
|
+
* (await both).unwrap(); // => [1, 2]
|
|
740
1066
|
* ```
|
|
741
1067
|
*/
|
|
742
1068
|
declare function allAsync<Rs extends readonly AsyncResult$1<unknown, unknown>[]>(results: readonly [...Rs]): AsyncResult$1<AllOk<Rs, { [K in keyof Rs]: AsyncOkOf<Rs[K]> }>, AsyncErrOf<Rs[number]>>;
|
|
@@ -748,10 +1074,17 @@ declare function allAsync<Rs extends readonly AsyncResult$1<unknown, unknown>[]>
|
|
|
748
1074
|
* Resolved concurrently (order preserved), folded with the {@link all} rules,
|
|
749
1075
|
* and the internal promise never rejects.
|
|
750
1076
|
*
|
|
1077
|
+
* @category Aggregate
|
|
1078
|
+
*
|
|
751
1079
|
* @example
|
|
752
1080
|
* ```ts
|
|
753
1081
|
* import { allFromDictAsync, fromSafePromise } from "unthrown";
|
|
754
|
-
*
|
|
1082
|
+
*
|
|
1083
|
+
* const both = allFromDictAsync({
|
|
1084
|
+
* a: fromSafePromise(Promise.resolve(1)),
|
|
1085
|
+
* b: fromSafePromise(Promise.resolve("x")),
|
|
1086
|
+
* });
|
|
1087
|
+
* (await both).unwrap(); // => { a: 1, b: "x" }
|
|
755
1088
|
* ```
|
|
756
1089
|
*/
|
|
757
1090
|
declare function allFromDictAsync<R extends AsyncResultRecord>(results: R): AsyncResult$1<{ [K in keyof R]: AsyncOkOf<R[K]> }, AsyncErrOf<R[keyof R]>>;
|
|
@@ -774,10 +1107,12 @@ declare function allFromDictAsync<R extends AsyncResultRecord>(results: R): Asyn
|
|
|
774
1107
|
* (`AsyncResult.fromPromise`, `AsyncResult.all`, …), grouped by what they
|
|
775
1108
|
* return — a static lives in exactly one namespace.
|
|
776
1109
|
*
|
|
1110
|
+
* @category Facade
|
|
1111
|
+
*
|
|
777
1112
|
* @example
|
|
778
1113
|
* ```ts
|
|
779
1114
|
* import { Result } from "unthrown";
|
|
780
|
-
* Result.Ok(1).flatMap((n) => Result.Ok(n + 1)).unwrap(); // 2
|
|
1115
|
+
* Result.Ok(1).flatMap((n) => Result.Ok(n + 1)).unwrap(); // => 2
|
|
781
1116
|
* ```
|
|
782
1117
|
*/
|
|
783
1118
|
declare const Result: {
|
|
@@ -793,6 +1128,20 @@ declare const Result: {
|
|
|
793
1128
|
readonly isDefect: typeof isDefect;
|
|
794
1129
|
readonly isResult: typeof isResult;
|
|
795
1130
|
};
|
|
1131
|
+
/**
|
|
1132
|
+
* `Result<T, E>` — the core discriminated union. Shares its name with the
|
|
1133
|
+
* {@link Result | companion object} above (the value and type are one name); this
|
|
1134
|
+
* is the type half.
|
|
1135
|
+
*
|
|
1136
|
+
* @remarks
|
|
1137
|
+
* A `Result` is a discriminated union, so TypeDoc can't list its methods on this
|
|
1138
|
+
* alias. Its fluent combinators (`map`, `flatMap`, `match`, `unwrap`, …) are
|
|
1139
|
+
* documented one per entry on {@link ResultMethods} — the shared method surface
|
|
1140
|
+
* every variant carries. For "which one do I reach for?", see the
|
|
1141
|
+
* [Choosing a combinator](/guide/choosing-a-combinator) guide.
|
|
1142
|
+
*
|
|
1143
|
+
* @category Facade
|
|
1144
|
+
*/
|
|
796
1145
|
type Result<T, E> = Result$1<T, E>;
|
|
797
1146
|
/**
|
|
798
1147
|
* Companion object grouping the **`AsyncResult`-producing** entry points under
|
|
@@ -809,10 +1158,13 @@ type Result<T, E> = Result$1<T, E>;
|
|
|
809
1158
|
* {@link Result}, the free functions remain the primary, tree-shakeable API; the
|
|
810
1159
|
* value `AsyncResult` and the type {@link AsyncResult} share one name.
|
|
811
1160
|
*
|
|
1161
|
+
* @category Facade
|
|
1162
|
+
*
|
|
812
1163
|
* @example
|
|
813
1164
|
* ```ts
|
|
814
1165
|
* import { AsyncResult } from "unthrown";
|
|
815
1166
|
* const user = await AsyncResult.fromPromise(fetchUser(id), (c, defect) => defect(c));
|
|
1167
|
+
* user.unwrap(); // => the fetched user (on success)
|
|
816
1168
|
* ```
|
|
817
1169
|
*/
|
|
818
1170
|
declare const AsyncResult: {
|
|
@@ -821,6 +1173,19 @@ declare const AsyncResult: {
|
|
|
821
1173
|
readonly all: typeof allAsync;
|
|
822
1174
|
readonly allFromDict: typeof allFromDictAsync;
|
|
823
1175
|
};
|
|
1176
|
+
/**
|
|
1177
|
+
* `AsyncResult<T, E>` — the async counterpart of {@link Result}. Shares its name
|
|
1178
|
+
* with the {@link AsyncResult | companion object} above (value and type are one
|
|
1179
|
+
* name); this is the type half.
|
|
1180
|
+
*
|
|
1181
|
+
* @remarks
|
|
1182
|
+
* `AsyncResult` carries the async fluent surface; its combinators (`map`,
|
|
1183
|
+
* `flatMap`, `match`, `unwrap`, …) are documented one per entry — with their
|
|
1184
|
+
* async signatures — on {@link AsyncResultMethods}. For "which one do I reach
|
|
1185
|
+
* for?", see the [Choosing a combinator](/guide/choosing-a-combinator) guide.
|
|
1186
|
+
*
|
|
1187
|
+
* @category Facade
|
|
1188
|
+
*/
|
|
824
1189
|
type AsyncResult<T, E> = AsyncResult$1<T, E>;
|
|
825
1190
|
//#endregion
|
|
826
1191
|
//#region src/tagged.d.ts
|
|
@@ -831,8 +1196,10 @@ type Props = Record<string, unknown>;
|
|
|
831
1196
|
*
|
|
832
1197
|
* @typeParam Tag - the string literal discriminant.
|
|
833
1198
|
* @typeParam A - the payload object type.
|
|
1199
|
+
*
|
|
1200
|
+
* @category Types
|
|
834
1201
|
*/
|
|
835
|
-
type TaggedErrorInstance<Tag extends string, A extends Props> = Error & Readonly<A
|
|
1202
|
+
type TaggedErrorInstance<Tag extends string, A extends Props> = Error & Readonly<Omit<A, "name">> & {
|
|
836
1203
|
readonly _tag: Tag;
|
|
837
1204
|
};
|
|
838
1205
|
/**
|
|
@@ -841,12 +1208,19 @@ type TaggedErrorInstance<Tag extends string, A extends Props> = Error & Readonly
|
|
|
841
1208
|
*
|
|
842
1209
|
* @remarks
|
|
843
1210
|
* When the payload is empty, the constructor takes **no** arguments (the
|
|
844
|
-
* `keyof A extends never ? void : A` trick); otherwise it takes the payload.
|
|
1211
|
+
* `keyof A extends never ? void : A` trick); otherwise it takes the payload. A
|
|
1212
|
+
* `name` key is **rejected** (`name?: never`) because it is reserved for the
|
|
1213
|
+
* display label — mirroring how {@link TaggedErrorInstance} excludes it — so the
|
|
1214
|
+
* reservation is enforced at the call site, not just ignored at runtime.
|
|
845
1215
|
*
|
|
846
1216
|
* @typeParam Tag - the string literal discriminant.
|
|
1217
|
+
*
|
|
1218
|
+
* @category Types
|
|
847
1219
|
*/
|
|
848
1220
|
type TaggedErrorConstructor<Tag extends string> = {
|
|
849
|
-
new <A extends Props = {}>(args: keyof A extends never ? void : A
|
|
1221
|
+
new <A extends Props = {}>(args: keyof A extends never ? void : A & {
|
|
1222
|
+
readonly name?: never;
|
|
1223
|
+
}): TaggedErrorInstance<Tag, A>;
|
|
850
1224
|
};
|
|
851
1225
|
/**
|
|
852
1226
|
* Build a base class for a tagged error — a class extending `Error` with a
|
|
@@ -856,7 +1230,10 @@ type TaggedErrorConstructor<Tag extends string> = {
|
|
|
856
1230
|
* Extend the returned class to declare a concrete error. Supply the payload with
|
|
857
1231
|
* an instantiation expression; omit it for a payload-less error. A `message`
|
|
858
1232
|
* field in the payload is forwarded to `Error`. The `_tag` always reflects
|
|
859
|
-
* `tag` and cannot be overridden by the payload.
|
|
1233
|
+
* `tag` and cannot be overridden by the payload. `name` is likewise reserved —
|
|
1234
|
+
* it is the display label (set it with `options.name`); a payload `name` is
|
|
1235
|
+
* rejected at compile time (and excluded from the instance type), so it can't
|
|
1236
|
+
* shadow `Error.name`.
|
|
860
1237
|
*
|
|
861
1238
|
* `_tag` is the discriminant used by {@link matchTags}; `Error.name` is the
|
|
862
1239
|
* human-facing label in stack traces and logs. By default they coincide, but
|
|
@@ -879,13 +1256,15 @@ type TaggedErrorConstructor<Tag extends string> = {
|
|
|
879
1256
|
* @param options - optional overrides. `options.name` sets `Error.name`
|
|
880
1257
|
* independently of `tag` (defaults to `tag`).
|
|
881
1258
|
*
|
|
1259
|
+
* @category Tagged errors
|
|
1260
|
+
*
|
|
882
1261
|
* @example
|
|
883
1262
|
* ```ts
|
|
884
1263
|
* class NotFound extends TaggedError("NotFound") {}
|
|
885
1264
|
* class HttpError extends TaggedError("HttpError")<{ status: number }> {}
|
|
886
1265
|
*
|
|
887
|
-
* new NotFound()._tag; // "NotFound"
|
|
888
|
-
* new HttpError({ status: 500 }).status; // 500
|
|
1266
|
+
* new NotFound()._tag; // => "NotFound"
|
|
1267
|
+
* new HttpError({ status: 500 }).status; // => 500
|
|
889
1268
|
* ```
|
|
890
1269
|
*/
|
|
891
1270
|
declare function TaggedError<Tag extends string>(tag: Tag, options?: {
|
|
@@ -899,6 +1278,8 @@ declare function TaggedError<Tag extends string>(tag: Tag, options?: {
|
|
|
899
1278
|
* @typeParam T - the success value type.
|
|
900
1279
|
* @typeParam E - the tagged error union.
|
|
901
1280
|
* @typeParam R - the folded result type.
|
|
1281
|
+
*
|
|
1282
|
+
* @category Types
|
|
902
1283
|
*/
|
|
903
1284
|
type TagHandlers<T, E extends {
|
|
904
1285
|
_tag: string;
|
|
@@ -908,6 +1289,14 @@ type TagHandlers<T, E extends {
|
|
|
908
1289
|
} & { [K in E["_tag"]]: (error: Extract<E, {
|
|
909
1290
|
_tag: K;
|
|
910
1291
|
}>) => R };
|
|
1292
|
+
/**
|
|
1293
|
+
* The channel-handler names are reserved: an error tag named `"Ok"` or
|
|
1294
|
+
* `"Defect"` would collide with them inside {@link TagHandlers}, so
|
|
1295
|
+
* {@link matchTags} rejects such unions at the call site.
|
|
1296
|
+
*
|
|
1297
|
+
* @internal
|
|
1298
|
+
*/
|
|
1299
|
+
type ReservedTagError = 'unthrown: error tags "Ok" and "Defect" are reserved by matchTags — rename the colliding tag (TaggedError\'s options.name can keep the display name)';
|
|
911
1300
|
/**
|
|
912
1301
|
* Exhaustively fold a {@link Result} (or {@link AsyncResult}) whose error type is
|
|
913
1302
|
* a tagged union, dispatching each error to the handler matching its `_tag`.
|
|
@@ -916,7 +1305,10 @@ type TagHandlers<T, E extends {
|
|
|
916
1305
|
* The `handlers` object must provide `Ok`, `Defect`, and exactly one function
|
|
917
1306
|
* per error tag; each tag's handler receives the narrowed error variant. A
|
|
918
1307
|
* missing tag is a compile error. For an `AsyncResult`, the fold resolves to a
|
|
919
|
-
* `Promise<R>`.
|
|
1308
|
+
* `Promise<R>`. At runtime, an error whose `_tag` has no handler (possible only
|
|
1309
|
+
* outside the typed contract) is routed to the `Defect` handler — an unmodeled
|
|
1310
|
+
* tag is an unmodeled failure. Tags named `"Ok"` or `"Defect"` are rejected at
|
|
1311
|
+
* compile time.
|
|
920
1312
|
*
|
|
921
1313
|
* @typeParam T - the success value type.
|
|
922
1314
|
* @typeParam E - the tagged error union (`E extends { _tag: string }`).
|
|
@@ -924,26 +1316,33 @@ type TagHandlers<T, E extends {
|
|
|
924
1316
|
* @param result - the result to fold.
|
|
925
1317
|
* @param handlers - one branch per channel/tag.
|
|
926
1318
|
*
|
|
1319
|
+
* @category Tagged errors
|
|
1320
|
+
*
|
|
927
1321
|
* @example
|
|
928
1322
|
* ```ts
|
|
1323
|
+
* import { Ok, Err, matchTags, TaggedError, type Result } from "unthrown";
|
|
1324
|
+
*
|
|
929
1325
|
* class NotFound extends TaggedError("NotFound") {}
|
|
930
1326
|
* class Forbidden extends TaggedError("Forbidden")<{ user: string }> {}
|
|
931
1327
|
*
|
|
932
|
-
*
|
|
933
|
-
*
|
|
934
|
-
*
|
|
935
|
-
*
|
|
936
|
-
*
|
|
937
|
-
*
|
|
938
|
-
*
|
|
1328
|
+
* const fold = (r: Result<number, NotFound | Forbidden>) =>
|
|
1329
|
+
* matchTags(r, {
|
|
1330
|
+
* Ok: (n) => `got ${n}`,
|
|
1331
|
+
* Defect: (cause) => `bug: ${String(cause)}`,
|
|
1332
|
+
* NotFound: () => "404",
|
|
1333
|
+
* Forbidden: (e) => `403 for ${e.user}`,
|
|
1334
|
+
* });
|
|
1335
|
+
*
|
|
1336
|
+
* fold(Ok(1)); // => "got 1"
|
|
1337
|
+
* fold(Err(new Forbidden({ user: "ada" }))); // => "403 for ada"
|
|
939
1338
|
* ```
|
|
940
1339
|
*/
|
|
941
1340
|
declare function matchTags<T, E extends {
|
|
942
1341
|
_tag: string;
|
|
943
|
-
}, R>(result: Result$1<T, E>, handlers: TagHandlers<T, E, R>): R;
|
|
1342
|
+
}, R>(result: Result$1<T, E>, handlers: TagHandlers<T, E, R> & ([Extract<E["_tag"], "Ok" | "Defect">] extends [never] ? unknown : ReservedTagError)): R;
|
|
944
1343
|
declare function matchTags<T, E extends {
|
|
945
1344
|
_tag: string;
|
|
946
|
-
}, R>(result: AsyncResult$1<T, E>, handlers: TagHandlers<T, E, R>): Promise<R>;
|
|
1345
|
+
}, R>(result: AsyncResult$1<T, E>, handlers: TagHandlers<T, E, R> & ([Extract<E["_tag"], "Ok" | "Defect">] extends [never] ? unknown : ReservedTagError)): Promise<R>;
|
|
947
1346
|
//#endregion
|
|
948
|
-
export { type AsyncErrOf, type AsyncOkOf, AsyncResult, type Awaitable, type DefectView, Do, Err, type ErrOf, type ErrView, Ok, type OkOf, type OkView, Result, type TagHandlers, TaggedError, type TaggedErrorConstructor, type TaggedErrorInstance, UnwrapError, all, allAsync, allFromDict, allFromDictAsync, fromNullable, fromPromise, fromSafePromise, fromThrowable, isDefect, isErr, isOk, isResult, matchTags };
|
|
1347
|
+
export { type AsyncErrOf, type AsyncOkOf, AsyncResult, type AsyncResultMethods, type Awaitable, type DefectView, Do, Err, type ErrOf, type ErrView, type NotThenable, Ok, type OkOf, type OkView, Result, type ResultMethods, type TagHandlers, TaggedError, type TaggedErrorConstructor, type TaggedErrorInstance, UnwrapError, all, allAsync, allFromDict, allFromDictAsync, fromNullable, fromPromise, fromSafePromise, fromThrowable, isDefect, isErr, isOk, isResult, matchTags };
|
|
949
1348
|
//# sourceMappingURL=index.d.cts.map
|