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 CHANGED
@@ -11,7 +11,10 @@ pnpm add unthrown
11
11
  ```
12
12
 
13
13
  ```ts
14
- import { Ok, Err, fromPromise, type Result } from "unthrown";
14
+ import { fromPromise, TaggedError } from "unthrown";
15
+
16
+ class NotFound extends TaggedError("NotFound") {} // our modeled domain failure
17
+ class NotFoundError extends Error {} // what `fetchUser` rejects with on a 404
15
18
 
16
19
  const user = fromPromise(fetchUser(id), (cause, defect) =>
17
20
  cause instanceof NotFoundError ? new NotFound() : defect(cause),
@@ -37,4 +40,4 @@ and complete API.
37
40
 
38
41
  ## License
39
42
 
40
- [MIT](../../LICENSE) © Benoit TRAVERS
43
+ [MIT](https://github.com/btravstack/unthrown/blob/main/LICENSE) © Benoit TRAVERS
package/dist/index.cjs CHANGED
@@ -15,6 +15,8 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
15
15
  * re-thrown (with its original stack) instead.
16
16
  *
17
17
  * @typeParam E - the type of the {@link UnwrapError.error} it carries.
18
+ *
19
+ * @category Errors
18
20
  */
19
21
  var UnwrapError = class extends Error {
20
22
  /**
@@ -129,7 +131,7 @@ var Res = class {
129
131
  f(this.error);
130
132
  return this;
131
133
  } catch (cause) {
132
- return defectRes(cause);
134
+ return observerThrowToDefect(cause, this.error);
133
135
  }
134
136
  }
135
137
  flatTapErr(f) {
@@ -138,7 +140,7 @@ var Res = class {
138
140
  const r = f(this.error);
139
141
  return r.tag === "Ok" ? this : passThrough(r);
140
142
  } catch (cause) {
141
- return defectRes(cause);
143
+ return observerThrowToDefect(cause, this.error);
142
144
  }
143
145
  }
144
146
  recoverDefect(f) {
@@ -155,7 +157,7 @@ var Res = class {
155
157
  f(this.cause);
156
158
  return this;
157
159
  } catch (cause) {
158
- return defectRes(cause);
160
+ return observerThrowToDefect(cause, this.cause);
159
161
  }
160
162
  }
161
163
  match(cases) {
@@ -218,10 +220,10 @@ const RESULT_PROTO = Res.prototype;
218
220
  * @internal
219
221
  */
220
222
  function okRes(value) {
221
- return Object.assign(Object.create(RESULT_PROTO), {
223
+ return Object.freeze(Object.assign(Object.create(RESULT_PROTO), {
222
224
  tag: "Ok",
223
225
  value
224
- });
226
+ }));
225
227
  }
226
228
  /**
227
229
  * Construct an `Err` result.
@@ -229,10 +231,10 @@ function okRes(value) {
229
231
  * @internal
230
232
  */
231
233
  function errRes(error) {
232
- return Object.assign(Object.create(RESULT_PROTO), {
234
+ return Object.freeze(Object.assign(Object.create(RESULT_PROTO), {
233
235
  tag: "Err",
234
236
  error
235
- });
237
+ }));
236
238
  }
237
239
  /**
238
240
  * Construct a `Defect` result.
@@ -240,10 +242,10 @@ function errRes(error) {
240
242
  * @internal
241
243
  */
242
244
  function defectRes(cause) {
243
- return Object.assign(Object.create(RESULT_PROTO), {
245
+ return Object.freeze(Object.assign(Object.create(RESULT_PROTO), {
244
246
  tag: "Defect",
245
247
  cause
246
- });
248
+ }));
247
249
  }
248
250
  /**
249
251
  * Type guard: is `x` a {@link Result} (any of `Ok` / `Err` / `Defect`)?
@@ -256,6 +258,20 @@ function defectRes(cause) {
256
258
  * is not a `Result` and returns `false`.
257
259
  *
258
260
  * @returns `true` when `x` is a `Result` produced by this library.
261
+ *
262
+ * @example
263
+ * ```ts
264
+ * import { isResult, Ok } from "unthrown";
265
+ *
266
+ * isResult(Ok(1)); // => true
267
+ * isResult({ tag: "Ok" }); // => false (look-alike, wrong prototype)
268
+ * isResult(Ok(1).toAsync()); // => false (an AsyncResult is not a Result)
269
+ *
270
+ * const x: unknown = Ok(1);
271
+ * if (isResult(x)) x.match({ ok: () => 1, err: () => 0, defect: () => -1 });
272
+ * ```
273
+ *
274
+ * @category Guards
259
275
  */
260
276
  function isResult(x) {
261
277
  return x instanceof Res;
@@ -274,6 +290,18 @@ function passThrough(self) {
274
290
  return self;
275
291
  }
276
292
  /**
293
+ * A throw inside a *failure observer* (`tapErr` / `tapDefect` / `flatTapErr`)
294
+ * must not destroy the failure being observed — that is the exact place (e.g. a
295
+ * failing error-logger) where losing the underlying failure hurts most. The
296
+ * resulting Defect aggregates both: `errors[0]` is the observer's throw,
297
+ * `errors[1]` the original failure.
298
+ *
299
+ * @internal
300
+ */
301
+ function observerThrowToDefect(thrown, original) {
302
+ return defectRes(new AggregateError([thrown, original], "unthrown: a failure-observer callback threw; errors[0] is the callback's throw, errors[1] the original failure"));
303
+ }
304
+ /**
277
305
  * Validate that a `bind`/`let` scope is a real (non-null) object before merging a
278
306
  * key into it.
279
307
  *
@@ -292,7 +320,7 @@ function passThrough(self) {
292
320
  * @internal
293
321
  */
294
322
  function scopeOf(value) {
295
- if (typeof value !== "object" || value === null) throw new TypeError("bind/let requires an object scope — start a do-chain with Do()");
323
+ if (typeof value !== "object" || value === null || Array.isArray(value)) throw new TypeError("bind/let requires an object scope — start a do-chain with Do()");
296
324
  return value;
297
325
  }
298
326
  /**
@@ -420,7 +448,7 @@ var AsyncRes = class AsyncRes {
420
448
  f(r.error);
421
449
  return r;
422
450
  } catch (cause) {
423
- return defectRes(cause);
451
+ return observerThrowToDefect(cause, r.error);
424
452
  }
425
453
  }));
426
454
  }
@@ -431,7 +459,7 @@ var AsyncRes = class AsyncRes {
431
459
  const inner = await f(r.error);
432
460
  return inner.tag === "Ok" ? passThrough(r) : passThrough(inner);
433
461
  } catch (cause) {
434
- return defectRes(cause);
462
+ return observerThrowToDefect(cause, r.error);
435
463
  }
436
464
  }));
437
465
  }
@@ -452,7 +480,7 @@ var AsyncRes = class AsyncRes {
452
480
  f(r.cause);
453
481
  return r;
454
482
  } catch (cause) {
455
- return defectRes(cause);
483
+ return observerThrowToDefect(cause, r.cause);
456
484
  }
457
485
  }));
458
486
  }
@@ -469,11 +497,7 @@ var AsyncRes = class AsyncRes {
469
497
  return this.promise.then((r) => r.unwrapOr(fallback));
470
498
  }
471
499
  unwrapOrElse(f) {
472
- return this.promise.then((r) => {
473
- if (r.tag === "Ok") return r.value;
474
- if (r.tag === "Defect") throw r.cause;
475
- return f(r.error);
476
- });
500
+ return this.promise.then((r) => r.unwrapOrElse(f));
477
501
  }
478
502
  getOrNull() {
479
503
  return this.promise.then((r) => r.getOrNull());
@@ -493,8 +517,12 @@ var AsyncRes = class AsyncRes {
493
517
  * @example
494
518
  * ```ts
495
519
  * import { Ok } from "unthrown";
496
- * Ok(42).unwrap(); // 42
520
+ *
521
+ * Ok(2).map((n) => n + 1); // => Ok(3)
522
+ * Ok(42).unwrap(); // => 42
497
523
  * ```
524
+ *
525
+ * @category Constructors
498
526
  */
499
527
  function Ok(value) {
500
528
  return okRes(value);
@@ -508,8 +536,12 @@ function Ok(value) {
508
536
  * @example
509
537
  * ```ts
510
538
  * import { Err } from "unthrown";
511
- * Err("not_found").unwrapErr(); // "not_found"
539
+ *
540
+ * Err("not_found").map((n) => n + 1); // => Err("not_found") (map skipped)
541
+ * Err("not_found").unwrapErr(); // => "not_found"
512
542
  * ```
543
+ *
544
+ * @category Constructors
513
545
  */
514
546
  function Err(error) {
515
547
  return errRes(error);
@@ -521,10 +553,16 @@ function Err(error) {
521
553
  *
522
554
  * @example
523
555
  * ```ts
524
- * import { isOk, type Result } from "unthrown";
556
+ * import { isOk, Ok, Err, type Result } from "unthrown";
557
+ *
558
+ * isOk(Ok(1)); // => true
559
+ * isOk(Err("boom")); // => false
560
+ *
525
561
  * declare const r: Result<number, string>;
526
562
  * if (isOk(r)) r.value; // number, narrowed
527
563
  * ```
564
+ *
565
+ * @category Guards
528
566
  */
529
567
  function isOk(r) {
530
568
  return r.tag === "Ok";
@@ -533,6 +571,19 @@ function isOk(r) {
533
571
  * Type guard: narrow a {@link Result} to its `Err` variant, exposing `.error`.
534
572
  *
535
573
  * @returns `true` when `r` is `Err`.
574
+ *
575
+ * @example
576
+ * ```ts
577
+ * import { isErr, Ok, Err, type Result } from "unthrown";
578
+ *
579
+ * isErr(Err("boom")); // => true
580
+ * isErr(Ok(1)); // => false
581
+ *
582
+ * declare const r: Result<number, string>;
583
+ * if (isErr(r)) r.error; // string, narrowed
584
+ * ```
585
+ *
586
+ * @category Guards
536
587
  */
537
588
  function isErr(r) {
538
589
  return r.tag === "Err";
@@ -540,7 +591,27 @@ function isErr(r) {
540
591
  /**
541
592
  * Type guard: narrow a {@link Result} to its `Defect` variant, exposing `.cause`.
542
593
  *
594
+ * @remarks
595
+ * A `Defect` has no public constructor — it only arises at a boundary (e.g. a
596
+ * callback throwing inside a combinator). This guard is how you detect one.
597
+ *
543
598
  * @returns `true` when `r` is a `Defect`.
599
+ *
600
+ * @example
601
+ * ```ts
602
+ * import { isDefect, Ok } from "unthrown";
603
+ *
604
+ * // A throw inside a combinator is captured as a Defect:
605
+ * const r = Ok(1).map(() => {
606
+ * throw new Error("boom");
607
+ * });
608
+ * isDefect(r); // => true
609
+ * isDefect(Ok(1)); // => false
610
+ *
611
+ * if (isDefect(r)) r.cause; // unknown, narrowed
612
+ * ```
613
+ *
614
+ * @category Guards
544
615
  */
545
616
  function isDefect(r) {
546
617
  return r.tag === "Defect";
@@ -568,6 +639,24 @@ function isDefect(r) {
568
639
  * .map(({ user, org, label }) => render(user, org, label));
569
640
  * // Result<View, NotFound>
570
641
  * ```
642
+ *
643
+ * @example
644
+ * ```ts
645
+ * import { Do, Ok, Err } from "unthrown";
646
+ *
647
+ * // Ok path — the scope accumulates:
648
+ * Do()
649
+ * .bind("a", () => Ok(2))
650
+ * .let("b", ({ a }) => a * 10)
651
+ * .map(({ a, b }) => a + b); // => Ok(22)
652
+ *
653
+ * // Err path — the first Err short-circuits the rest:
654
+ * Do()
655
+ * .bind("a", () => Err("boom"))
656
+ * .let("b", ({ a }) => a); // => Err("boom")
657
+ * ```
658
+ *
659
+ * @category Do-notation
571
660
  */
572
661
  function Do() {
573
662
  return Ok({});
@@ -617,10 +706,16 @@ function isDefectMarker(x) {
617
706
  * @param value - the possibly-absent value.
618
707
  * @param onAbsent - lazily produces the error for the absent case.
619
708
  *
709
+ * @category Interop
710
+ *
620
711
  * @example
621
712
  * ```ts
622
713
  * import { fromNullable } from "unthrown";
623
- * fromNullable(map.get(key), () => "missing").unwrap();
714
+ *
715
+ * const map = new Map([["a", 1]]);
716
+ * fromNullable(map.get("a"), () => "absent").unwrap(); // => 1
717
+ * fromNullable(map.get("z"), () => "absent"); // => Err("absent")
718
+ * fromNullable(0, () => "absent").unwrap(); // => 0 (falsy but present)
624
719
  * ```
625
720
  */
626
721
  function fromNullable(value, onAbsent) {
@@ -651,11 +746,21 @@ function fromNullable(value, onAbsent) {
651
746
  * unmodeled by returning `defect(cause)` (the helper passed as its second arg).
652
747
  * @returns a function with the same arguments returning `Result<T, E>`.
653
748
  *
749
+ * @category Interop
750
+ *
654
751
  * @example
655
752
  * ```ts
656
753
  * import { fromThrowable } from "unthrown";
657
- * const parse = fromThrowable(JSON.parse, (cause, defect) => defect(cause));
658
- * parse("{}").unwrap();
754
+ *
755
+ * // Model the parse failure as an `Err`, everything unexpected as a `Defect`.
756
+ * const parse = fromThrowable(
757
+ * (text: string) => JSON.parse(text) as unknown,
758
+ * (cause, defect) =>
759
+ * cause instanceof SyntaxError ? ("invalid_json" as const) : defect(cause),
760
+ * );
761
+ *
762
+ * parse('{"ok":true}').unwrap(); // => { ok: true }
763
+ * parse("nope"); // => Err("invalid_json")
659
764
  * ```
660
765
  */
661
766
  function fromThrowable(fn, qualify) {
@@ -690,17 +795,24 @@ function fromThrowable(fn, qualify) {
690
795
  * @param qualify - triages a rejection `cause` into a modeled `E`, or marks it
691
796
  * unmodeled by returning `defect(cause)` (the helper passed as its second arg).
692
797
  *
798
+ * @category Interop
799
+ *
693
800
  * @example
694
801
  * ```ts
695
802
  * import { fromPromise } from "unthrown";
803
+ *
804
+ * // A rejection with a NotFoundError becomes a modeled `Err`; anything else a Defect.
696
805
  * const user = await fromPromise(fetchUser(id), (cause, defect) =>
697
806
  * cause instanceof NotFoundError ? ("not_found" as const) : defect(cause),
698
807
  * );
808
+ *
809
+ * user.unwrap(); // => the fetched user (on success)
810
+ * // when fetchUser rejects with NotFoundError: => Err("not_found")
699
811
  * ```
700
812
  */
701
813
  function fromPromise(promise, qualify) {
702
814
  const triage = qualify;
703
- return new AsyncRes((typeof promise === "function" ? Promise.resolve().then(promise) : promise).then((value) => okRes(value), (cause) => qualifyToResult(cause, triage)));
815
+ return new AsyncRes((typeof promise === "function" ? Promise.resolve().then(promise) : Promise.resolve(promise)).then((value) => okRes(value), (cause) => qualifyToResult(cause, triage)));
704
816
  }
705
817
  /**
706
818
  * Wrap a `Promise` asserted **not** to fail in any modeled way: any rejection
@@ -713,9 +825,20 @@ function fromPromise(promise, qualify) {
713
825
  *
714
826
  * @typeParam T - the resolved value type.
715
827
  * @param promise - the promise, or a thunk returning one.
828
+ *
829
+ * @category Interop
830
+ *
831
+ * @example
832
+ * ```ts
833
+ * import { fromSafePromise } from "unthrown";
834
+ *
835
+ * (await fromSafePromise(Promise.resolve(3))).unwrap(); // => 3
836
+ * // a rejection becomes a Defect (never a modeled Err):
837
+ * await fromSafePromise(Promise.reject(new Error("boom"))); // => Defect(Error("boom"))
838
+ * ```
716
839
  */
717
840
  function fromSafePromise(promise) {
718
- return new AsyncRes((typeof promise === "function" ? Promise.resolve().then(promise) : promise).then((value) => okRes(value), (cause) => defectRes(cause)));
841
+ return new AsyncRes((typeof promise === "function" ? Promise.resolve().then(promise) : Promise.resolve(promise)).then((value) => okRes(value), (cause) => defectRes(cause)));
719
842
  }
720
843
  function qualifyToResult(cause, qualify) {
721
844
  try {
@@ -735,8 +858,10 @@ function foldArray(results) {
735
858
  let firstErr;
736
859
  let firstDefect;
737
860
  const values = [];
738
- for (const r of results) if (r.tag === "Defect") firstDefect ??= r;
739
- else if (r.tag === "Err") firstErr ??= r;
861
+ for (const r of results) if (r.tag === "Defect") {
862
+ firstDefect ??= r;
863
+ break;
864
+ } else if (r.tag === "Err") firstErr ??= r;
740
865
  else values.push(r.value);
741
866
  return firstDefect ?? firstErr ?? Ok(values);
742
867
  }
@@ -751,8 +876,10 @@ function foldRecord(results) {
751
876
  let firstErr;
752
877
  let firstDefect;
753
878
  const values = {};
754
- for (const [key, r] of Object.entries(results)) if (r.tag === "Defect") firstDefect ??= r;
755
- else if (r.tag === "Err") firstErr ??= r;
879
+ for (const [key, r] of Object.entries(results)) if (r.tag === "Defect") {
880
+ firstDefect ??= r;
881
+ break;
882
+ } else if (r.tag === "Err") firstErr ??= r;
756
883
  else Object.defineProperty(values, key, {
757
884
  value: r.value,
758
885
  enumerable: true,
@@ -773,11 +900,14 @@ function foldRecord(results) {
773
900
  * collapses to `Result<T[], E>` with no cast. For a **record** keyed by name,
774
901
  * use {@link allFromDict}.
775
902
  *
903
+ * @category Aggregate
904
+ *
776
905
  * @example
777
906
  * ```ts
778
- * import { all, Ok } from "unthrown";
779
- * all([Ok(1), Ok("a"), Ok(true)]).unwrap(); // [1, "a", true] (typed [number, string, boolean])
780
- * all([Ok(1), Ok(2)] as Result<number, never>[]).unwrap(); // number[]
907
+ * import { all, Ok, Err } from "unthrown";
908
+ *
909
+ * all([Ok(1), Ok("a"), Ok(true)]).unwrap(); // => [1, "a", true] (typed [number, string, boolean])
910
+ * all([Ok(1), Err("e"), Ok(3)]); // => Err("e") (short-circuits on the first Err)
781
911
  * ```
782
912
  */
783
913
  function all(results) {
@@ -793,10 +923,14 @@ function all(results) {
793
923
  * Same folding rules as {@link all}: first `Err` short-circuits, any `Defect`
794
924
  * dominates. This is **not** error accumulation.
795
925
  *
926
+ * @category Aggregate
927
+ *
796
928
  * @example
797
929
  * ```ts
798
- * import { allFromDict, Ok } from "unthrown";
799
- * allFromDict({ id: Ok(1), name: Ok("ada") }).unwrap(); // { id: 1, name: "ada" }
930
+ * import { allFromDict, Ok, Err } from "unthrown";
931
+ *
932
+ * allFromDict({ id: Ok(1), name: Ok("ada") }).unwrap(); // => { id: 1, name: "ada" }
933
+ * allFromDict({ id: Ok(1), name: Err("missing") }); // => Err("missing")
800
934
  * ```
801
935
  */
802
936
  function allFromDict(results) {
@@ -812,10 +946,14 @@ function allFromDict(results) {
812
946
  * short-circuits, any `Defect` dominates. As ever, the returned `AsyncResult`'s
813
947
  * internal promise never rejects. For a **record**, use {@link allFromDictAsync}.
814
948
  *
949
+ * @category Aggregate
950
+ *
815
951
  * @example
816
952
  * ```ts
817
953
  * import { allAsync, fromSafePromise } from "unthrown";
818
- * await allAsync([fromSafePromise(a()), fromSafePromise(b())]);
954
+ *
955
+ * const both = allAsync([fromSafePromise(Promise.resolve(1)), fromSafePromise(Promise.resolve(2))]);
956
+ * (await both).unwrap(); // => [1, 2]
819
957
  * ```
820
958
  */
821
959
  function allAsync(results) {
@@ -829,10 +967,17 @@ function allAsync(results) {
829
967
  * Resolved concurrently (order preserved), folded with the {@link all} rules,
830
968
  * and the internal promise never rejects.
831
969
  *
970
+ * @category Aggregate
971
+ *
832
972
  * @example
833
973
  * ```ts
834
974
  * import { allFromDictAsync, fromSafePromise } from "unthrown";
835
- * await allFromDictAsync({ a: fromSafePromise(a()), b: fromSafePromise(b()) });
975
+ *
976
+ * const both = allFromDictAsync({
977
+ * a: fromSafePromise(Promise.resolve(1)),
978
+ * b: fromSafePromise(Promise.resolve("x")),
979
+ * });
980
+ * (await both).unwrap(); // => { a: 1, b: "x" }
836
981
  * ```
837
982
  */
838
983
  function allFromDictAsync(results) {
@@ -864,10 +1009,12 @@ function allFromDictAsync(results) {
864
1009
  * (`AsyncResult.fromPromise`, `AsyncResult.all`, …), grouped by what they
865
1010
  * return — a static lives in exactly one namespace.
866
1011
  *
1012
+ * @category Facade
1013
+ *
867
1014
  * @example
868
1015
  * ```ts
869
1016
  * import { Result } from "unthrown";
870
- * Result.Ok(1).flatMap((n) => Result.Ok(n + 1)).unwrap(); // 2
1017
+ * Result.Ok(1).flatMap((n) => Result.Ok(n + 1)).unwrap(); // => 2
871
1018
  * ```
872
1019
  */
873
1020
  const Result = {
@@ -898,10 +1045,13 @@ const Result = {
898
1045
  * {@link Result}, the free functions remain the primary, tree-shakeable API; the
899
1046
  * value `AsyncResult` and the type {@link AsyncResult} share one name.
900
1047
  *
1048
+ * @category Facade
1049
+ *
901
1050
  * @example
902
1051
  * ```ts
903
1052
  * import { AsyncResult } from "unthrown";
904
1053
  * const user = await AsyncResult.fromPromise(fetchUser(id), (c, defect) => defect(c));
1054
+ * user.unwrap(); // => the fetched user (on success)
905
1055
  * ```
906
1056
  */
907
1057
  const AsyncResult = {
@@ -920,7 +1070,10 @@ const AsyncResult = {
920
1070
  * Extend the returned class to declare a concrete error. Supply the payload with
921
1071
  * an instantiation expression; omit it for a payload-less error. A `message`
922
1072
  * field in the payload is forwarded to `Error`. The `_tag` always reflects
923
- * `tag` and cannot be overridden by the payload.
1073
+ * `tag` and cannot be overridden by the payload. `name` is likewise reserved —
1074
+ * it is the display label (set it with `options.name`); a payload `name` is
1075
+ * rejected at compile time (and excluded from the instance type), so it can't
1076
+ * shadow `Error.name`.
924
1077
  *
925
1078
  * `_tag` is the discriminant used by {@link matchTags}; `Error.name` is the
926
1079
  * human-facing label in stack traces and logs. By default they coincide, but
@@ -943,13 +1096,15 @@ const AsyncResult = {
943
1096
  * @param options - optional overrides. `options.name` sets `Error.name`
944
1097
  * independently of `tag` (defaults to `tag`).
945
1098
  *
1099
+ * @category Tagged errors
1100
+ *
946
1101
  * @example
947
1102
  * ```ts
948
1103
  * class NotFound extends TaggedError("NotFound") {}
949
1104
  * class HttpError extends TaggedError("HttpError")<{ status: number }> {}
950
1105
  *
951
- * new NotFound()._tag; // "NotFound"
952
- * new HttpError({ status: 500 }).status; // 500
1106
+ * new NotFound()._tag; // => "NotFound"
1107
+ * new HttpError({ status: 500 }).status; // => 500
953
1108
  * ```
954
1109
  */
955
1110
  function TaggedError(tag, options) {
@@ -968,8 +1123,9 @@ function TaggedError(tag, options) {
968
1123
  }
969
1124
  function matchTags(result, handlers) {
970
1125
  const onErr = (error) => {
971
- const handler = handlers[error._tag];
972
- return handler(error);
1126
+ const tag = error._tag;
1127
+ const handler = tag === "Ok" || tag === "Defect" || !Object.hasOwn(handlers, tag) ? void 0 : handlers[tag];
1128
+ return handler ? handler(error) : handlers.Defect(error);
973
1129
  };
974
1130
  return result.match({
975
1131
  ok: handlers.Ok,