unthrown 4.3.0 → 5.0.0-beta.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/dist/index.d.cts CHANGED
@@ -1,3 +1,25 @@
1
+ import { P, match, match as match$1 } from "ts-pattern";
2
+ //#region src/defect.d.ts
3
+ declare const DEFECT: unique symbol;
4
+ /**
5
+ * The opaque marker a `qualify` function returns to triage a cause as
6
+ * **unexpected**.
7
+ *
8
+ * @remarks
9
+ * `qualify` (passed to {@link fromPromise} / {@link fromThrowable}) returns
10
+ * `E | Defect`: either a modeled domain error, or a `Defect` produced by the
11
+ * injected `defect` helper to say "this failure is not modeled". A `Defect` is
12
+ * opaque — it carries the original cause for the boundary to convert into the
13
+ * third runtime state of a `Result`. It is **not** a public value; the only way
14
+ * to mint one is the `defect` helper the boundary passes to `qualify`.
15
+ *
16
+ * @internal
17
+ */
18
+ type Defect = {
19
+ readonly [DEFECT]: true;
20
+ readonly cause: unknown;
21
+ };
22
+ //#endregion
1
23
  //#region src/types.d.ts
2
24
  /**
3
25
  * Flatten an intersection into a single object literal so accumulated `bind` /
@@ -32,6 +54,49 @@ type Bound<T, K extends string, U> = Prettify<Omit<T, K> & { readonly [P in K]:
32
54
  * @category Types
33
55
  */
34
56
  type NotThenable<R> = [R] extends [PromiseLike<unknown>] ? "unthrown: combinator callbacks are synchronous — lift async work with fromPromise and compose with flatMap" : unknown;
57
+ /**
58
+ * The ts-pattern match builder over an error union `E`, as produced by
59
+ * `match(error)`. This is what an error combinator's callback receives — chain
60
+ * `.with(pattern, handler)` on it; the combinator itself calls `.exhaustive()`,
61
+ * so the callback returns the **un-terminated** builder.
62
+ *
63
+ * @remarks
64
+ * Named via `ReturnType<typeof match<E>>` so the internal ts-pattern `Match`
65
+ * type (not part of ts-pattern's public exports) never has to be imported.
66
+ *
67
+ * @typeParam E - the error union being matched.
68
+ * @category Types
69
+ */
70
+ type ErrMatcher<E> = ReturnType<typeof match$1<E>>;
71
+ /**
72
+ * The shape an error-combinator callback must return: an **exhaustive**
73
+ * ts-pattern builder. `exhaustive` is required to be *callable* — on a builder
74
+ * that hasn't covered every case ts-pattern types it as a `NonExhaustiveError`
75
+ * (not a function), so a non-exhaustive chain fails to satisfy this and errors
76
+ * at the call site. `run` carries the output type.
77
+ *
78
+ * @typeParam O - the union of the branch return types (the builder's output).
79
+ * @internal
80
+ */
81
+ type ExhaustiveMatch<O> = {
82
+ exhaustive: (...args: never[]) => unknown;
83
+ run: () => O;
84
+ };
85
+ /**
86
+ * The output of an `ExhaustiveMatch` — the union of its branch returns.
87
+ *
88
+ * @internal
89
+ */
90
+ type MatchOut<M> = M extends ExhaustiveMatch<infer O> ? O : never;
91
+ /**
92
+ * The outgoing modeled-error type a transforming match produces: the builder's
93
+ * output with the `Defect` arm **subtracted** (`Exclude<O, Defect>`, the same
94
+ * inference as the boundary `qualify`, Thesis #3). A branch that returns
95
+ * `defect(cause)` therefore contributes nothing to the modeled channel.
96
+ *
97
+ * @internal
98
+ */
99
+ type MatchErrOut<M> = Exclude<MatchOut<M>, Defect>;
35
100
  /**
36
101
  * The fluent method surface every {@link Result} variant carries — the
37
102
  * combinators (`map`, `flatMap`, `mapErr`, `match`, `get`, …), documented one
@@ -48,7 +113,7 @@ type NotThenable<R> = [R] extends [PromiseLike<unknown>] ? "unthrown: combinator
48
113
  * @typeParam E - the modeled error type.
49
114
  * @category Methods
50
115
  */
51
- type ResultMethods<T, E> = {
116
+ type ResultMethods<out T, out E> = {
52
117
  /**
53
118
  * Transform the success value with `f`.
54
119
  *
@@ -162,103 +227,90 @@ type ResultMethods<T, E> = {
162
227
  */
163
228
  discard(): Result$1<void, E>;
164
229
  /**
165
- * Transform the modeled error with `f`.
230
+ * Transform the modeled error by **matching it exhaustively** with ts-pattern.
166
231
  *
167
- * Runs `f` only on `Err`; `Ok` passes through and a `Defect` is **never**
168
- * touched. If `f` throws, the throw becomes a `Defect`. An async callback is
169
- * rejected at compile time ({@link NotThenable}).
170
- *
171
- * @typeParam E2 - the mapped error type.
172
- * @param f - maps the current error to a new one.
173
- */
174
- mapErr<E2>(f: (error: E) => E2 & NotThenable<E2>): Result$1<T, E2>;
175
- /**
176
- * Sequence from an `Err` by producing another `Result` — the error-channel
177
- * mirror of {@link ResultMethods.flatMap | flatMap}.
232
+ * @remarks
233
+ * The callback receives `match(error)` (an {@link ErrMatcher}) and the
234
+ * injected `defect` helper. Chain `.with(pattern, handler)` and **return the
235
+ * un-terminated builder** — `mapErr` calls `.exhaustive()` itself, so a
236
+ * missing case is a compile error at the call site (there is no `.exhaustive()`
237
+ * to forget, and no way to slip in `.otherwise()`). The outgoing error type is
238
+ * the union of the branch returns with the `Defect` arm subtracted
239
+ * (`Exclude<O, Defect>`) — a branch returning `defect(cause)` converts that case
240
+ * to a `Defect` and drops it from `E`. Runs only on `Err`; `Ok` and `Defect`
241
+ * pass through. A branch that throws also becomes a `Defect`.
178
242
  *
179
- * Runs `f` only on `Err`; `Ok` and `Defect` pass through. If `f` throws, the
180
- * throw becomes a `Defect`.
243
+ * `.with(P._, …)` is the deliberate uniform/catch-all (it makes the match
244
+ * exhaustive). Match on anything ts-pattern supports — `_tag`, `code`,
245
+ * structural shape, guards, or grouped patterns `.with(a, b, handler)`.
181
246
  *
182
- * @typeParam U - an alternative success type `f` may produce.
183
- * @typeParam E2 - the error type `f` may produce instead.
184
- * @param f - produces a fallback `Result` from the current error.
247
+ * @typeParam M - the exhaustive builder the callback returns.
248
+ * @param f - builds the match over the error (returns the un-terminated builder).
185
249
  */
186
- flatMapErr<U, E2>(f: (error: E) => Result$1<U, E2>): Result$1<T | U, E2>;
250
+ mapErr<M extends ExhaustiveMatch<unknown>>(f: (matcher: ErrMatcher<E>, defect: (cause: unknown) => Defect) => M): Result$1<T, MatchErrOut<M>>;
187
251
  /**
188
- * Sequence from an `Err` by producing another `Result`.
252
+ * Sequence from an `Err` by producing another `Result` — the error-channel
253
+ * mirror of {@link ResultMethods.flatMap | flatMap}, **matching the error
254
+ * exhaustively** ({@link ErrMatcher}; the combinator calls `.exhaustive()`).
189
255
  *
190
- * @deprecated Renamed to {@link ResultMethods.flatMapErr | flatMapErr} — it is
191
- * `flatMap` on the error channel, so it now follows the `…Err` convention. This
192
- * alias will be removed in a future major.
256
+ * Each branch returns a `Result`; the outgoing channels are the unions of the
257
+ * branch-returned `Result`s' channels. A branch may return `defect(cause)`.
258
+ * Runs only on `Err`; `Ok` and `Defect` pass through.
193
259
  *
194
- * @typeParam U - an alternative success type `f` may produce.
195
- * @typeParam E2 - the error type `f` may produce instead.
196
- * @param f - produces a fallback `Result` from the current error.
260
+ * @typeParam M - the exhaustive builder the callback returns.
261
+ * @param f - builds the match; each branch produces a fallback `Result`.
197
262
  */
198
- orElse<U, E2>(f: (error: E) => Result$1<U, E2>): Result$1<T | U, E2>;
263
+ flatMapErr<M extends ExhaustiveMatch<Result$1<unknown, unknown> | Defect>>(f: (matcher: ErrMatcher<E>, defect: (cause: unknown) => Defect) => M): Result$1<T | OkOf<MatchOut<M>>, ErrOf<MatchOut<M>>>;
199
264
  /**
200
265
  * Recover from an `Err` by producing a success value, emptying the error
201
- * channel. Pairs with {@link ResultMethods.recoverDefect | recoverDefect}.
266
+ * channel — **matching the error exhaustively** ({@link ErrMatcher}). Pairs
267
+ * with {@link ResultMethods.recoverDefect | recoverDefect}.
202
268
  *
203
269
  * @remarks
204
270
  * The result type is `Result<T | U, never>`, but `never` describes only the
205
- * **error** channel — a `Defect` can still be present at runtime, so do not
206
- * read `never` as "total". Runs `f` only on `Err`; `Ok` and `Defect` pass
207
- * through. If `f` throws, the throw becomes a `Defect`. An async callback is
208
- * rejected at compile time ({@link NotThenable}).
209
- *
210
- * @typeParam U - the recovered success type.
211
- * @param f - produces a success value from the current error.
212
- */
213
- recoverErr<U>(f: (error: E) => U & NotThenable<U>): Result$1<T | U, never>;
214
- /**
215
- * Recover from an `Err` by producing a success value.
271
+ * **error** channel — a `Defect` can still be present at runtime. A branch may
272
+ * return `defect(cause)` (which stays a `Defect`, not a recovery). Runs only on
273
+ * `Err`; `Ok` and `Defect` pass through.
216
274
  *
217
- * @deprecated Renamed to {@link ResultMethods.recoverErr | recoverErr} — it now
218
- * pairs with {@link ResultMethods.recoverDefect | recoverDefect} and follows the
219
- * `…Err` convention. This alias will be removed in a future major.
220
- *
221
- * @typeParam U - the recovered success type.
222
- * @param f - produces a success value from the current error.
275
+ * @typeParam M - the exhaustive builder the callback returns.
276
+ * @param f - builds the match; each branch produces a success value.
223
277
  */
224
- recover<U>(f: (error: E) => U & NotThenable<U>): Result$1<T | U, never>;
278
+ recoverErr<M extends ExhaustiveMatch<unknown>>(f: (matcher: ErrMatcher<E>, defect: (cause: unknown) => Defect) => M): Result$1<T | MatchErrOut<M>, never>;
225
279
  /**
226
- * Run a side effect on the error and pass the `Result` through unchanged.
227
- *
228
- * Runs only on `Err`. If `f` throws, the result is a `Defect` whose cause is
229
- * an `AggregateError` of `[thrown, original failure]` — observing a failure
230
- * never destroys it. An async callback is rejected at compile time
231
- * ({@link NotThenable}).
280
+ * Run a side effect on the error — **matched exhaustively** ({@link ErrMatcher})
281
+ * — and pass the `Result` through unchanged.
232
282
  *
233
283
  * @remarks
234
- * As with {@link ResultMethods.tap | tap}, `f`'s return value is ignored — a
235
- * failable `Result`-returning effect belongs in
236
- * {@link ResultMethods.flatTapErr | flatTapErr}; an `AsyncResult`-returning
237
- * one needs the chain lifted with {@link ResultMethods.toAsync | toAsync}
238
- * first (the async {@link AsyncResultMethods.flatTapErr | flatTapErr}
239
- * accepts both).
284
+ * The callback builds a match whose branches run side effects; their return
285
+ * values are ignored and the original `Err` flows through. Exhaustive like the
286
+ * transformers (use `.with(P._, …)` for a catch-all). If a branch throws, the
287
+ * result is a `Defect` whose cause is an `AggregateError` of `[thrown, original
288
+ * failure]` — observing a failure never destroys it. A failable
289
+ * `Result`-returning effect belongs in
290
+ * {@link ResultMethods.flatTapErr | flatTapErr}.
240
291
  *
241
- * @param f - the side effect (its return value is ignored).
292
+ * @param f - builds the match; branch returns are ignored.
242
293
  */
243
- tapErr<R>(f: (error: E) => R & NotThenable<R>): Result$1<T, E>;
294
+ tapErr(f: (matcher: ErrMatcher<E>, defect: (cause: unknown) => Defect) => ExhaustiveMatch<unknown>): Result$1<T, E>;
244
295
  /**
245
296
  * Run a **failable** side effect on the error, keeping the original error but
246
- * threading the effect's own error.
297
+ * threading the effect's own error — **matched exhaustively**
298
+ * ({@link ErrMatcher}).
247
299
  *
248
300
  * @remarks
249
- * The error-channel mirror of {@link ResultMethods.flatTap | flatTap}: `f`
250
- * returns a `Result`, but its **success value is discarded** — on the effect's
251
- * `Ok` the original `Err` flows through unchanged, while an `Err` (or `Defect`)
252
- * from `f` short-circuits and threads its error (`Result<T, E | E2>`). Runs only
253
- * on `Err`; `Ok` and `Defect` pass through. If `f` throws, the result is a
254
- * `Defect` whose cause is an `AggregateError` of `[thrown, original failure]` —
255
- * observing a failure never destroys it. Use it for a failable effect _during_
256
- * error handling (e.g. writing the error to an audit log that may itself fail).
301
+ * The error-channel mirror of {@link ResultMethods.flatTap | flatTap}: each
302
+ * branch returns a `Result` whose **success value is discarded** — on the
303
+ * effect's `Ok` the original `Err` flows through, while an `Err`/`Defect` from a
304
+ * branch short-circuits and threads its error. Note the asymmetry with a
305
+ * *throw*: a branch that **returns** a `Defect` **replaces** the original `Err`
306
+ * (Defect-dominance, the short-circuit rule — it is not aggregated), whereas a
307
+ * branch that **throws** produces a `Defect` aggregating `[thrown, original
308
+ * failure]` (observing a failure by throwing never destroys it).
257
309
  *
258
- * @typeParam E2 - the error type the effect may introduce.
259
- * @param f - the failable side effect; its `Ok` value is ignored.
310
+ * @typeParam M - the exhaustive builder the callback returns.
311
+ * @param f - builds the match; each branch is a failable effect (its `Ok` is ignored).
260
312
  */
261
- flatTapErr<E2>(f: (error: E) => Result$1<unknown, E2>): Result$1<T, E | E2>;
313
+ flatTapErr<E2>(f: (matcher: ErrMatcher<E>, defect: (cause: unknown) => Defect) => ExhaustiveMatch<Result$1<unknown, E2>>): Result$1<T, E | E2>;
262
314
  /**
263
315
  * Recover from a `Defect` — the **only** combinator that can touch one.
264
316
  *
@@ -309,23 +361,34 @@ type ResultMethods<T, E> = {
309
361
  */
310
362
  tapFailure<R>(f: (failure: FailureView<E, T>) => R & NotThenable<R>): Result$1<T, E>;
311
363
  /**
312
- * Exhaustively fold all three runtime states into a single value of type `R`.
364
+ * Exhaustively fold all three runtime states into a single value.
313
365
  *
314
366
  * @remarks
315
367
  * Exactly one handler runs. Together with the throw-to-Defect guarantee, this
316
368
  * is typically the single place a pipeline is handled at the edge — mapping
317
369
  * `Ok`/`Err`/`Defect` to (for example) 2xx / 4xx / 5xx with no `try`/`catch`.
318
- * (For richer matching, a `Result` is also a discriminated union — branch on
319
- * its `tag` property, e.g. with `ts-pattern`.)
320
370
  *
321
- * @typeParam R - the folded result type.
322
- * @param cases - one handler per channel.
371
+ * The `err` handler does not take a single blanket callback: it receives
372
+ * `match(error)` (an {@link ErrMatcher}) and **matches the error exhaustively**,
373
+ * exactly like the error combinators. Chain `.with(pattern, handler)` and
374
+ * **return the un-terminated builder** — `match` calls `.exhaustive()` itself,
375
+ * so a missing case is a compile error at the call site (no `.exhaustive()` to
376
+ * forget). Use `.with(P._, …)` for a uniform catch-all. Unlike the combinators
377
+ * the branches receive **no `defect` helper** — `match` is total elimination
378
+ * to a value, with no `Defect` output channel; the `defect` case handles a
379
+ * `Result` that already carries one. (A `Result` is also a discriminated
380
+ * union — for richer whole-`Result` matching, `match(result).with(…)`.)
381
+ *
382
+ * @typeParam ROk - the `ok` handler return type.
383
+ * @typeParam RDefect - the `defect` handler return type.
384
+ * @typeParam M - the exhaustive builder the `err` handler returns.
385
+ * @param cases - the `ok`/`defect` handlers plus the `err` matcher builder.
323
386
  */
324
- match<R>(cases: {
325
- ok: (value: T) => R;
326
- err: (error: E) => R;
327
- defect: (cause: unknown) => R;
328
- }): R;
387
+ match<ROk, RDefect, M extends ExhaustiveMatch<unknown>>(cases: {
388
+ ok: (value: T) => ROk;
389
+ err: (matcher: ErrMatcher<E>) => M;
390
+ defect: (cause: unknown) => RDefect;
391
+ }): ROk | RDefect | MatchOut<M>;
329
392
  /**
330
393
  * Extract the success value.
331
394
  *
@@ -343,15 +406,6 @@ type ResultMethods<T, E> = {
343
406
  * @returns the `Ok` value.
344
407
  */
345
408
  get(this: Result$1<T, never>): T;
346
- /**
347
- * Extract the success value.
348
- *
349
- * @deprecated Renamed to {@link ResultMethods.get | get}, unifying the extractor
350
- * family under `get…`. This alias will be removed in a future major.
351
- *
352
- * @returns the `Ok` value.
353
- */
354
- unwrap(this: Result$1<T, never>): T;
355
409
  /**
356
410
  * Extract the modeled error.
357
411
  *
@@ -366,15 +420,6 @@ type ResultMethods<T, E> = {
366
420
  * @returns the `Err` value.
367
421
  */
368
422
  getErr(this: Result$1<never, E>): E;
369
- /**
370
- * Extract the modeled error.
371
- *
372
- * @deprecated Renamed to {@link ResultMethods.getErr | getErr}, unifying the
373
- * extractor family under `get…`. This alias will be removed in a future major.
374
- *
375
- * @returns the `Err` value.
376
- */
377
- unwrapErr(this: Result$1<never, E>): E;
378
423
  /**
379
424
  * The success value, or `fallback` on `Err`.
380
425
  *
@@ -384,17 +429,6 @@ type ResultMethods<T, E> = {
384
429
  * it is never silently replaced.
385
430
  */
386
431
  getOr<U>(fallback: U): T | U;
387
- /**
388
- * The success value, or `fallback` on `Err`.
389
- *
390
- * @deprecated Renamed to {@link ResultMethods.getOr | getOr}, unifying the
391
- * extractor family under `get…`. This alias will be removed in a future major.
392
- *
393
- * @typeParam U - the fallback type (may differ from `T`; the return widens to `T | U`).
394
- * @param fallback - returned when the result is an `Err`.
395
- * @throws Re-throws on a `Defect`.
396
- */
397
- unwrapOr<U>(fallback: U): T | U;
398
432
  /**
399
433
  * The success value, or `f(error)` on `Err`.
400
434
  *
@@ -403,17 +437,6 @@ type ResultMethods<T, E> = {
403
437
  * @throws Re-throws on a `Defect`.
404
438
  */
405
439
  getOrElse<U>(f: (error: E) => U): T | U;
406
- /**
407
- * The success value, or `f(error)` on `Err`.
408
- *
409
- * @deprecated Renamed to {@link ResultMethods.getOrElse | getOrElse}, unifying
410
- * the extractor family under `get…`. This alias will be removed in a future major.
411
- *
412
- * @typeParam U - the fallback type (may differ from `T`; the return widens to `T | U`).
413
- * @param f - lazily computes the fallback from the error.
414
- * @throws Re-throws on a `Defect`.
415
- */
416
- unwrapOrElse<U>(f: (error: E) => U): T | U;
417
440
  /**
418
441
  * The success value, or `null` on `Err`.
419
442
  *
@@ -430,20 +453,26 @@ type ResultMethods<T, E> = {
430
453
  * The success value, or **throw** the modeled error on `Err`.
431
454
  *
432
455
  * @remarks
433
- * A deliberate escape hatch off the errors-as-values model. Unlike
434
- * {@link ResultMethods.get | get} (type-gated to an empty error
435
- * channel), this compiles on any `Result<T, E>` and **throws the `Err` value
436
- * as-is** at the call site. Its purpose is to move a literal `throw` behind a
437
- * method, so a `no-throw` lint rule can ban raw throws while this one
438
- * sanctioned extraction remains — _not_ to replace principled handling. When
439
- * you can keep the error a value, prefer {@link ResultMethods.match | match} /
440
- * {@link ResultMethods.recoverErr | recoverErr} / {@link ResultMethods.flatMapErr | flatMapErr}.
456
+ * A deliberate escape hatch off the errors-as-values model — it **throws the
457
+ * `Err` value as-is** at the call site. Its purpose is to move a literal
458
+ * `throw` behind a method, so a `no-throw` lint rule can ban raw throws while
459
+ * this one sanctioned extraction remains — _not_ to replace principled
460
+ * handling. When you can keep the error a value, prefer
461
+ * {@link ResultMethods.match | match} / {@link ResultMethods.recoverErr | recoverErr} /
462
+ * {@link ResultMethods.flatMapErr | flatMapErr}.
463
+ *
464
+ * Type-gated as the **complement** of {@link ResultMethods.get | get}: it
465
+ * compiles only when the error channel is **non-empty** (`E` is not `never`) —
466
+ * there must be a modeled error for it to throw. On a `Result<T, never>` there
467
+ * is nothing to throw, so `getOrThrow` does not compile; use `get()` (which
468
+ * gates the other way). Together they partition extraction by the error
469
+ * channel's state, with no overlap.
441
470
  *
442
471
  * @returns the `Ok` value.
443
472
  * @throws the modeled `error` on `Err`; re-throws the original `cause` on a
444
473
  * `Defect` (a panic, like the rest of the `getOr…` family).
445
474
  */
446
- getOrThrow(): T;
475
+ getOrThrow(this: [E] extends [never] ? never : Result$1<T, E>): T;
447
476
  /** Whether this result is `Ok` — narrows `this` to its {@link OkView} on `true`. */
448
477
  isOk(): this is OkView<T, E>;
449
478
  /** Whether this result is `Err` — narrows `this` to its {@link ErrView} on `true`. */
@@ -589,7 +618,7 @@ type Result$1<T, E> = OkView<T, E> | ErrView<E, T> | DefectView<T, E>;
589
618
  *
590
619
  * @category Types
591
620
  */
592
- type Awaitable<T> = {
621
+ type Awaitable<out T> = {
593
622
  then<R = T>(onfulfilled?: ((value: T) => R | PromiseLike<R>) | null): PromiseLike<R>;
594
623
  };
595
624
  /**
@@ -612,7 +641,7 @@ type Awaitable<T> = {
612
641
  * @typeParam E - the modeled error type.
613
642
  * @category Methods
614
643
  */
615
- type AsyncResultMethods<T, E> = {
644
+ type AsyncResultMethods<out T, out E> = {
616
645
  /**
617
646
  * Asynchronous {@link ResultMethods.map | map}: transforms the success value
618
647
  * with `f`. `f` is synchronous; a throw becomes a `Defect`. An async callback
@@ -660,32 +689,22 @@ type AsyncResultMethods<T, E> = {
660
689
  /** Asynchronous {@link ResultMethods.discard | discard}: drops the value, collapsing the success type to `void`. */
661
690
  discard(): AsyncResult$1<void, E>;
662
691
  /**
663
- * Asynchronous {@link ResultMethods.mapErr | mapErr}. `f` is synchronous; a
664
- * throw becomes a `Defect`. An async callback is rejected at compile time
665
- * ({@link NotThenable}).
692
+ * Asynchronous {@link ResultMethods.mapErr | mapErr} — the same exhaustive
693
+ * {@link ErrMatcher} form; the combinator calls `.exhaustive()`.
666
694
  */
667
- mapErr<E2>(f: (error: E) => E2 & NotThenable<E2>): AsyncResult$1<T, E2>;
695
+ mapErr<M extends ExhaustiveMatch<unknown>>(f: (matcher: ErrMatcher<E>, defect: (cause: unknown) => Defect) => M): AsyncResult$1<T, MatchErrOut<M>>;
668
696
  /**
669
- * Asynchronous {@link ResultMethods.flatMapErr | flatMapErr}. `f` may return a
670
- * `Result` or an `AsyncResult`.
697
+ * Asynchronous {@link ResultMethods.flatMapErr | flatMapErr} — the same
698
+ * exhaustive {@link ErrMatcher} form. Unlike the sync form, a branch may
699
+ * return a `Result` **or** an `AsyncResult`.
671
700
  */
672
- flatMapErr<U, E2>(f: (error: E) => Result$1<U, E2> | AsyncResult$1<U, E2>): AsyncResult$1<T | U, E2>;
701
+ flatMapErr<M extends ExhaustiveMatch<Result$1<unknown, unknown> | AsyncResult$1<unknown, unknown> | Defect>>(f: (matcher: ErrMatcher<E>, defect: (cause: unknown) => Defect) => M): AsyncResult$1<T | OkOf<MatchOut<M>> | AsyncOkOf<MatchOut<M>>, ErrOf<MatchOut<M>> | AsyncErrOf<MatchOut<M>>>;
673
702
  /**
674
- * @deprecated Renamed to {@link AsyncResultMethods.flatMapErr | flatMapErr}.
675
- * This alias will be removed in a future major.
676
- */
677
- orElse<U, E2>(f: (error: E) => Result$1<U, E2> | AsyncResult$1<U, E2>): AsyncResult$1<T | U, E2>;
678
- /**
679
- * Asynchronous {@link ResultMethods.recoverErr | recoverErr}. `f` is
680
- * synchronous; a throw becomes a `Defect`. An async callback is rejected at
681
- * compile time ({@link NotThenable}).
682
- */
683
- recoverErr<U>(f: (error: E) => U & NotThenable<U>): AsyncResult$1<T | U, never>;
684
- /**
685
- * @deprecated Renamed to {@link AsyncResultMethods.recoverErr | recoverErr}.
686
- * This alias will be removed in a future major.
703
+ * Asynchronous {@link ResultMethods.recoverErr | recoverErr} — the same
704
+ * exhaustive {@link ErrMatcher} form. Branches are synchronous; a throw
705
+ * becomes a `Defect`.
687
706
  */
688
- recover<U>(f: (error: E) => U & NotThenable<U>): AsyncResult$1<T | U, never>;
707
+ recoverErr<M extends ExhaustiveMatch<unknown>>(f: (matcher: ErrMatcher<E>, defect: (cause: unknown) => Defect) => M): AsyncResult$1<T | MatchErrOut<M>, never>;
689
708
  /**
690
709
  * Asynchronous {@link ResultMethods.tapErr | tapErr}. `f` is synchronous; if it
691
710
  * throws, the result is a `Defect` whose cause is an `AggregateError` of
@@ -695,7 +714,7 @@ type AsyncResultMethods<T, E> = {
695
714
  * too — a failable effect belongs in
696
715
  * {@link AsyncResultMethods.flatTapErr | flatTapErr}.
697
716
  */
698
- tapErr<R>(f: (error: E) => R & NotThenable<R>): AsyncResult$1<T, E>;
717
+ tapErr(f: (matcher: ErrMatcher<E>, defect: (cause: unknown) => Defect) => ExhaustiveMatch<unknown>): AsyncResult$1<T, E>;
699
718
  /**
700
719
  * Asynchronous {@link ResultMethods.flatTapErr | flatTapErr} — the
701
720
  * error-channel mirror of `flatTap`. `f` may return a `Result` **or** an
@@ -704,7 +723,7 @@ type AsyncResultMethods<T, E> = {
704
723
  * an `AggregateError` of `[thrown, original failure]` — observing a failure
705
724
  * never destroys it.
706
725
  */
707
- flatTapErr<E2>(f: (error: E) => Result$1<unknown, E2> | AsyncResult$1<unknown, E2>): AsyncResult$1<T, E | E2>;
726
+ flatTapErr<E2>(f: (matcher: ErrMatcher<E>, defect: (cause: unknown) => Defect) => ExhaustiveMatch<Result$1<unknown, E2> | AsyncResult$1<unknown, E2>>): AsyncResult$1<T, E | E2>;
708
727
  /**
709
728
  * Asynchronous {@link ResultMethods.recoverDefect | recoverDefect}. `f` may
710
729
  * return a `Result` or an `AsyncResult`.
@@ -727,50 +746,31 @@ type AsyncResultMethods<T, E> = {
727
746
  */
728
747
  tapFailure<R>(f: (failure: FailureView<E, T>) => R & NotThenable<R>): AsyncResult$1<T, E>;
729
748
  /**
730
- * Asynchronous {@link ResultMethods.match | match}. Handlers are synchronous;
731
- * resolves to a `Promise<R>`.
749
+ * Asynchronous {@link ResultMethods.match | match}. Handlers are synchronous
750
+ * (the `err` handler returns an exhaustive {@link ErrMatcher} builder, no
751
+ * `defect` helper); resolves to a `Promise` of the folded value.
732
752
  */
733
- match<R>(cases: {
734
- ok: (value: T) => R;
735
- err: (error: E) => R;
736
- defect: (cause: unknown) => R;
737
- }): Promise<R>;
753
+ match<ROk, RDefect, M extends ExhaustiveMatch<unknown>>(cases: {
754
+ ok: (value: T) => ROk;
755
+ err: (matcher: ErrMatcher<E>) => M;
756
+ defect: (cause: unknown) => RDefect;
757
+ }): Promise<ROk | RDefect | MatchOut<M>>;
738
758
  /**
739
759
  * Asynchronous {@link ResultMethods.get | get}. Compiles only when the
740
760
  * error channel is empty (`this: AsyncResult<T, never>`); the returned promise
741
761
  * rejects on a `Defect` (rethrowing its cause).
742
762
  */
743
763
  get(this: AsyncResult$1<T, never>): Promise<T>;
744
- /**
745
- * @deprecated Renamed to {@link AsyncResultMethods.get | get}. This alias will
746
- * be removed in a future major.
747
- */
748
- unwrap(this: AsyncResult$1<T, never>): Promise<T>;
749
764
  /**
750
765
  * Asynchronous {@link ResultMethods.getErr | getErr}. Compiles only when
751
766
  * the success channel is empty (`this: AsyncResult<never, E>`); the returned
752
767
  * promise rejects on a `Defect` (rethrowing its cause).
753
768
  */
754
769
  getErr(this: AsyncResult$1<never, E>): Promise<E>;
755
- /**
756
- * @deprecated Renamed to {@link AsyncResultMethods.getErr | getErr}. This alias
757
- * will be removed in a future major.
758
- */
759
- unwrapErr(this: AsyncResult$1<never, E>): Promise<E>;
760
770
  /** Asynchronous {@link ResultMethods.getOr | getOr}. */
761
771
  getOr<U>(fallback: U): Promise<T | U>;
762
- /**
763
- * @deprecated Renamed to {@link AsyncResultMethods.getOr | getOr}. This alias
764
- * will be removed in a future major.
765
- */
766
- unwrapOr<U>(fallback: U): Promise<T | U>;
767
772
  /** Asynchronous {@link ResultMethods.getOrElse | getOrElse}. */
768
773
  getOrElse<U>(f: (error: E) => U): Promise<T | U>;
769
- /**
770
- * @deprecated Renamed to {@link AsyncResultMethods.getOrElse | getOrElse}. This
771
- * alias will be removed in a future major.
772
- */
773
- unwrapOrElse<U>(f: (error: E) => U): Promise<T | U>;
774
774
  /** Asynchronous {@link ResultMethods.getOrNull | getOrNull}. */
775
775
  getOrNull(): Promise<T | null>;
776
776
  /** Asynchronous {@link ResultMethods.getOrUndefined | getOrUndefined}. */
@@ -778,9 +778,10 @@ type AsyncResultMethods<T, E> = {
778
778
  /**
779
779
  * Asynchronous {@link ResultMethods.getOrThrow | getOrThrow} — the returned
780
780
  * promise **rejects** with the modeled error on `Err` (or the original cause
781
- * on a `Defect`), rather than throwing synchronously.
781
+ * on a `Defect`), rather than throwing synchronously. Gated the same way: it
782
+ * compiles only when the error channel is non-empty (`E` is not `never`).
782
783
  */
783
- getOrThrow(): Promise<T>;
784
+ getOrThrow(this: [E] extends [never] ? never : AsyncResult$1<T, E>): Promise<T>;
784
785
  };
785
786
  /**
786
787
  * The asynchronous counterpart of {@link Result}: an awaitable wrapper carrying
@@ -853,7 +854,7 @@ type ErrOf<R> = R extends {
853
854
  *
854
855
  * @category Types
855
856
  */
856
- type AsyncOkOf<R> = R extends AsyncResult$1<infer T, unknown> ? T : never;
857
+ type AsyncOkOf<R> = R extends Awaitable<infer Res> ? OkOf<Res> : never;
857
858
  /**
858
859
  * Extract the error type `E` from an {@link AsyncResult} type — the async
859
860
  * counterpart of {@link ErrOf}.
@@ -867,7 +868,7 @@ type AsyncOkOf<R> = R extends AsyncResult$1<infer T, unknown> ? T : never;
867
868
  *
868
869
  * @category Types
869
870
  */
870
- type AsyncErrOf<R> = R extends AsyncResult$1<unknown, infer E> ? E : never;
871
+ type AsyncErrOf<R> = R extends Awaitable<infer Res> ? ErrOf<Res> : never;
871
872
  //#endregion
872
873
  //#region src/constructors.d.ts
873
874
  /**
@@ -1054,12 +1055,12 @@ declare function isDefect<T, E>(r: Result$1<T, E>): r is DefectView<T, E>;
1054
1055
  * `Ok`.
1055
1056
  *
1056
1057
  * @remarks
1057
- * The offending value is exposed two ways: the typed {@link UnwrapError.error}
1058
+ * The offending value is exposed two ways: the typed {@link GetError.error}
1058
1059
  * property for programmatic access, and the standard `Error.cause` for the
1059
1060
  * runtime and devtools to chain — when `E` is an `Error` (e.g. a `TaggedError`)
1060
1061
  * its original stack is printed under "caused by".
1061
1062
  *
1062
- * A `Defect` is never wrapped in an `UnwrapError`: its original cause is
1063
+ * A `Defect` is never wrapped in a `GetError`: its original cause is
1063
1064
  * re-thrown (with its original stack) instead.
1064
1065
  *
1065
1066
  * `get()` and `getErr()` are type-gated (`this: Result<T, never>` /
@@ -1067,11 +1068,11 @@ declare function isDefect<T, E>(r: Result$1<T, E>): r is DefectView<T, E>;
1067
1068
  * unreachable through well-typed code — it remains only as a defensive guard
1068
1069
  * against unsound runtime misuse (e.g. an `as` cast past the gate).
1069
1070
  *
1070
- * @typeParam E - the type of the {@link UnwrapError.error} it carries.
1071
+ * @typeParam E - the type of the {@link GetError.error} it carries.
1071
1072
  *
1072
1073
  * @category Errors
1073
1074
  */
1074
- declare class UnwrapError<E = unknown> extends Error {
1075
+ declare class GetError<E = unknown> extends Error {
1075
1076
  /**
1076
1077
  * The offending value: the `Err` error for `get()`, or the `Ok` value for
1077
1078
  * `getErr()`.
@@ -1150,27 +1151,6 @@ declare function isResult(x: unknown): x is Result$1<unknown, unknown>;
1150
1151
  */
1151
1152
  declare function Do(): Result$1<{}, never>;
1152
1153
  //#endregion
1153
- //#region src/defect.d.ts
1154
- declare const DEFECT: unique symbol;
1155
- /**
1156
- * The opaque marker a `qualify` function returns to triage a cause as
1157
- * **unexpected**.
1158
- *
1159
- * @remarks
1160
- * `qualify` (passed to {@link fromPromise} / {@link fromThrowable}) returns
1161
- * `E | Defect`: either a modeled domain error, or a `Defect` produced by the
1162
- * injected `defect` helper to say "this failure is not modeled". A `Defect` is
1163
- * opaque — it carries the original cause for the boundary to convert into the
1164
- * third runtime state of a `Result`. It is **not** a public value; the only way
1165
- * to mint one is the `defect` helper the boundary passes to `qualify`.
1166
- *
1167
- * @internal
1168
- */
1169
- type Defect = {
1170
- readonly [DEFECT]: true;
1171
- readonly cause: unknown;
1172
- };
1173
- //#endregion
1174
1154
  //#region src/interop.d.ts
1175
1155
  /**
1176
1156
  * Bridge a nullable value into a {@link Result}: absence becomes a **modeled**
@@ -1605,8 +1585,10 @@ type TaggedErrorConstructor<Tag extends string> = {
1605
1585
  * rejected at compile time (and excluded from the instance type), so it can't
1606
1586
  * shadow `Error.name`.
1607
1587
  *
1608
- * `_tag` is the discriminant used by {@link matchTags}; `Error.name` is the
1609
- * human-facing label in stack traces and logs. By default they coincide, but
1588
+ * `_tag` is the discriminant matched by {@link tag} in the error combinators
1589
+ * (`result.mapErr((matcher) => matcher.with(tag("NotFound"), …))`) and in
1590
+ * `match`; `Error.name` is the human-facing label in stack traces and logs. By
1591
+ * default they coincide, but
1610
1592
  * they can be **decoupled** with `options.name` — so a tag can be namespaced for
1611
1593
  * collision-safety (`"@my-lib/RetryableError"`) without that slash-prefixed
1612
1594
  * string leaking into `Error.name`:
@@ -1644,78 +1626,28 @@ declare function TaggedError<Tag extends string>(tag: Tag, options?: {
1644
1626
  readonly name?: string;
1645
1627
  }): TaggedErrorConstructor<Tag>;
1646
1628
  /**
1647
- * The handler object {@link matchTags} requires: a branch per error tag, plus
1648
- * `Ok` and `Defect`. Miss a tag and it will not compile — the exhaustiveness is
1649
- * enforced by the type, with no `.exhaustive()` to forget.
1629
+ * A `ts-pattern` pattern matching any value whose `_tag` equals `value` — a
1630
+ * {@link TaggedError}, or any discriminated member. Equivalent to the object
1631
+ * pattern `{ _tag: value }`, but reads better inside an error-matching
1632
+ * combinator and narrows to the matching variant, payload included.
1650
1633
  *
1651
- * @typeParam T - the success value type.
1652
- * @typeParam E - the tagged error union.
1653
- * @typeParam R - the folded result type.
1654
- *
1655
- * @category Types
1656
- */
1657
- type TagHandlers<T, E extends {
1658
- _tag: string;
1659
- }, R> = {
1660
- Ok: (value: T) => R;
1661
- Defect: (cause: unknown) => R;
1662
- } & { [K in E["_tag"]]: (error: Extract<E, {
1663
- _tag: K;
1664
- }>) => R; };
1665
- /**
1666
- * The channel-handler names are reserved: an error tag named `"Ok"` or
1667
- * `"Defect"` would collide with them inside {@link TagHandlers}, so
1668
- * {@link matchTags} rejects such unions at the call site.
1669
- *
1670
- * @internal
1671
- */
1672
- 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)';
1673
- /**
1674
- * Exhaustively fold a {@link Result} (or {@link AsyncResult}) whose error type is
1675
- * a tagged union, dispatching each error to the handler matching its `_tag`.
1676
- *
1677
- * @remarks
1678
- * The `handlers` object must provide `Ok`, `Defect`, and exactly one function
1679
- * per error tag; each tag's handler receives the narrowed error variant. A
1680
- * missing tag is a compile error. For an `AsyncResult`, the fold resolves to a
1681
- * `Promise<R>`. At runtime, an error whose `_tag` has no handler (possible only
1682
- * outside the typed contract) is routed to the `Defect` handler — an unmodeled
1683
- * tag is an unmodeled failure. Tags named `"Ok"` or `"Defect"` are rejected at
1684
- * compile time.
1685
- *
1686
- * @typeParam T - the success value type.
1687
- * @typeParam E - the tagged error union (`E extends { _tag: string }`).
1688
- * @typeParam R - the folded result type.
1689
- * @param result - the result to fold.
1690
- * @param handlers - one branch per channel/tag.
1634
+ * @typeParam Tag - the string literal tag to match.
1635
+ * @param value - the `_tag` to match.
1691
1636
  *
1692
1637
  * @category Tagged errors
1693
1638
  *
1694
1639
  * @example
1695
1640
  * ```ts
1696
- * import { Ok, Err, matchTags, TaggedError, type Result } from "unthrown";
1697
- *
1698
- * class NotFound extends TaggedError("NotFound") {}
1699
- * class Forbidden extends TaggedError("Forbidden")<{ user: string }> {}
1700
- *
1701
- * const fold = (r: Result<number, NotFound | Forbidden>) =>
1702
- * matchTags(r, {
1703
- * Ok: (n) => `got ${n}`,
1704
- * Defect: (cause) => `bug: ${String(cause)}`,
1705
- * NotFound: () => "404",
1706
- * Forbidden: (e) => `403 for ${e.user}`,
1707
- * });
1708
- *
1709
- * fold(Ok(1)); // => "got 1"
1710
- * fold(Err(new Forbidden({ user: "ada" }))); // => "403 for ada"
1641
+ * result.mapErr((matcher) =>
1642
+ * matcher
1643
+ * .with(tag("NotFound"), () => new NotFoundException())
1644
+ * .with(tag("Conflict"), (e) => new ConflictException(e.key)),
1645
+ * );
1711
1646
  * ```
1712
1647
  */
1713
- declare function matchTags<T, E extends {
1714
- _tag: string;
1715
- }, R>(result: Result$1<T, E>, handlers: TagHandlers<T, E, R> & ([Extract<E["_tag"], "Ok" | "Defect">] extends [never] ? unknown : ReservedTagError)): R;
1716
- declare function matchTags<T, E extends {
1717
- _tag: string;
1718
- }, R>(result: AsyncResult$1<T, E>, handlers: TagHandlers<T, E, R> & ([Extract<E["_tag"], "Ok" | "Defect">] extends [never] ? unknown : ReservedTagError)): Promise<R>;
1648
+ declare function tag<const Tag extends string>(value: Tag): {
1649
+ _tag: Tag;
1650
+ };
1719
1651
  //#endregion
1720
- export { type AsyncErrOf, type AsyncOkOf, AsyncResult, type AsyncResultMethods, type Awaitable, type DefectView, Do, Err, ErrAsync, type ErrOf, type ErrView, type FailureView, type NotThenable, Ok, OkAsync, type OkOf, type OkView, Result, type ResultMethods, type TagHandlers, TaggedError, type TaggedErrorConstructor, type TaggedErrorInstance, UnwrapError, all, allAsync, allFromDict, allFromDictAsync, fromNullable, fromPromise, fromSafePromise, fromSafeThrowable, fromThrowable, isDefect, isErr, isOk, isResult, matchTags };
1652
+ export { type AsyncErrOf, type AsyncOkOf, AsyncResult, type AsyncResultMethods, type Awaitable, type DefectView, Do, Err, ErrAsync, type ErrMatcher, type ErrOf, type ErrView, type FailureView, GetError, type NotThenable, Ok, OkAsync, type OkOf, type OkView, P, Result, type ResultMethods, TaggedError, type TaggedErrorConstructor, type TaggedErrorInstance, all, allAsync, allFromDict, allFromDictAsync, fromNullable, fromPromise, fromSafePromise, fromSafeThrowable, fromThrowable, isDefect, isErr, isOk, isResult, match, tag };
1721
1653
  //# sourceMappingURL=index.d.cts.map