unthrown 4.0.0 → 4.2.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.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  //#region src/core.ts
3
3
  /**
4
- * Thrown by a {@link Result}'s `unwrap` / `unwrapErr` when the assertion is
5
- * wrong on a *modeled* result — `unwrap()` on an `Err`, or `unwrapErr()` on an
4
+ * Thrown by a {@link Result}'s `get` / `getErr` when the assertion is
5
+ * wrong on a *modeled* result — `get()` on an `Err`, or `getErr()` on an
6
6
  * `Ok`.
7
7
  *
8
8
  * @remarks
@@ -14,7 +14,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
14
14
  * A `Defect` is never wrapped in an `UnwrapError`: its original cause is
15
15
  * re-thrown (with its original stack) instead.
16
16
  *
17
- * `unwrap()` and `unwrapErr()` are type-gated (`this: Result<T, never>` /
17
+ * `get()` and `getErr()` are type-gated (`this: Result<T, never>` /
18
18
  * `Result<never, E>`), so the wrong-variant branch that throws this is
19
19
  * unreachable through well-typed code — it remains only as a defensive guard
20
20
  * against unsound runtime misuse (e.g. an `as` cast past the gate).
@@ -25,8 +25,8 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
25
25
  */
26
26
  var UnwrapError = class extends Error {
27
27
  /**
28
- * The offending value: the `Err` error for `unwrap()`, or the `Ok` value for
29
- * `unwrapErr()`.
28
+ * The offending value: the `Err` error for `get()`, or the `Ok` value for
29
+ * `getErr()`.
30
30
  */
31
31
  error;
32
32
  constructor(error) {
@@ -106,6 +106,10 @@ var Res = class {
106
106
  if (this.tag !== "Ok") return passThrough(this);
107
107
  return okRes(value);
108
108
  }
109
+ discard() {
110
+ if (this.tag !== "Ok") return passThrough(this);
111
+ return okRes(void 0);
112
+ }
109
113
  mapErr(f) {
110
114
  if (this.tag !== "Err") return passThrough(this);
111
115
  try {
@@ -114,7 +118,7 @@ var Res = class {
114
118
  return defectRes(cause);
115
119
  }
116
120
  }
117
- orElse(f) {
121
+ flatMapErr(f) {
118
122
  if (this.tag !== "Err") return passThrough(this);
119
123
  try {
120
124
  return f(this.error);
@@ -122,7 +126,11 @@ var Res = class {
122
126
  return defectRes(cause);
123
127
  }
124
128
  }
125
- recover(f) {
129
+ /** @deprecated Use {@link Res.flatMapErr}. */
130
+ orElse(f) {
131
+ return this.flatMapErr(f);
132
+ }
133
+ recoverErr(f) {
126
134
  if (this.tag !== "Err") return passThrough(this);
127
135
  try {
128
136
  return okRes(f(this.error));
@@ -130,6 +138,10 @@ var Res = class {
130
138
  return defectRes(cause);
131
139
  }
132
140
  }
141
+ /** @deprecated Use {@link Res.recoverErr}. */
142
+ recover(f) {
143
+ return this.recoverErr(f);
144
+ }
133
145
  tapErr(f) {
134
146
  if (this.tag !== "Err") return this;
135
147
  try {
@@ -172,30 +184,46 @@ var Res = class {
172
184
  case "Defect": return cases.defect(this.cause);
173
185
  }
174
186
  }
175
- unwrap() {
187
+ get() {
176
188
  switch (this.tag) {
177
189
  case "Ok": return this.value;
178
190
  case "Err": throw new UnwrapError(this.error);
179
191
  case "Defect": throw this.cause;
180
192
  }
181
193
  }
182
- unwrapErr() {
194
+ /** @deprecated Use {@link Res.get}. */
195
+ unwrap() {
196
+ return this.get();
197
+ }
198
+ getErr() {
183
199
  switch (this.tag) {
184
200
  case "Err": return this.error;
185
201
  case "Ok": throw new UnwrapError(this.value);
186
202
  case "Defect": throw this.cause;
187
203
  }
188
204
  }
189
- unwrapOr(fallback) {
205
+ /** @deprecated Use {@link Res.getErr}. */
206
+ unwrapErr() {
207
+ return this.getErr();
208
+ }
209
+ getOr(fallback) {
190
210
  if (this.tag === "Ok") return this.value;
191
211
  if (this.tag === "Defect") throw this.cause;
192
212
  return fallback;
193
213
  }
194
- unwrapOrElse(f) {
214
+ /** @deprecated Use {@link Res.getOr}. */
215
+ unwrapOr(fallback) {
216
+ return this.getOr(fallback);
217
+ }
218
+ getOrElse(f) {
195
219
  if (this.tag === "Ok") return this.value;
196
220
  if (this.tag === "Defect") throw this.cause;
197
221
  return f(this.error);
198
222
  }
223
+ /** @deprecated Use {@link Res.getOrElse}. */
224
+ unwrapOrElse(f) {
225
+ return this.getOrElse(f);
226
+ }
199
227
  getOrNull() {
200
228
  if (this.tag === "Ok") return this.value;
201
229
  if (this.tag === "Defect") throw this.cause;
@@ -205,6 +233,11 @@ var Res = class {
205
233
  if (this.tag === "Ok") return this.value;
206
234
  if (this.tag === "Defect") throw this.cause;
207
235
  }
236
+ getOrThrow() {
237
+ if (this.tag === "Ok") return this.value;
238
+ if (this.tag === "Defect") throw this.cause;
239
+ throw this.error;
240
+ }
208
241
  isOk() {
209
242
  return this.tag === "Ok";
210
243
  }
@@ -416,6 +449,9 @@ var AsyncRes = class AsyncRes {
416
449
  as(value) {
417
450
  return new AsyncRes(this.promise.then((r) => r.tag === "Ok" ? okRes(value) : passThrough(r)));
418
451
  }
452
+ discard() {
453
+ return new AsyncRes(this.promise.then((r) => r.tag === "Ok" ? okRes(void 0) : passThrough(r)));
454
+ }
419
455
  mapErr(f) {
420
456
  return new AsyncRes(this.promise.then((r) => {
421
457
  if (r.tag !== "Err") return passThrough(r);
@@ -426,7 +462,7 @@ var AsyncRes = class AsyncRes {
426
462
  }
427
463
  }));
428
464
  }
429
- orElse(f) {
465
+ flatMapErr(f) {
430
466
  return new AsyncRes(this.promise.then(async (r) => {
431
467
  if (r.tag !== "Err") return passThrough(r);
432
468
  try {
@@ -436,7 +472,11 @@ var AsyncRes = class AsyncRes {
436
472
  }
437
473
  }));
438
474
  }
439
- recover(f) {
475
+ /** @deprecated Use {@link AsyncRes.flatMapErr}. */
476
+ orElse(f) {
477
+ return this.flatMapErr(f);
478
+ }
479
+ recoverErr(f) {
440
480
  return new AsyncRes(this.promise.then((r) => {
441
481
  if (r.tag !== "Err") return passThrough(r);
442
482
  try {
@@ -446,6 +486,10 @@ var AsyncRes = class AsyncRes {
446
486
  }
447
487
  }));
448
488
  }
489
+ /** @deprecated Use {@link AsyncRes.recoverErr}. */
490
+ recover(f) {
491
+ return this.recoverErr(f);
492
+ }
449
493
  tapErr(f) {
450
494
  return new AsyncRes(this.promise.then((r) => {
451
495
  if (r.tag !== "Err") return r;
@@ -492,17 +536,33 @@ var AsyncRes = class AsyncRes {
492
536
  match(cases) {
493
537
  return this.promise.then((r) => r.match(cases));
494
538
  }
539
+ get() {
540
+ return this.promise.then((r) => r.get());
541
+ }
542
+ /** @deprecated Use {@link AsyncRes.get}. */
495
543
  unwrap() {
496
- return this.promise.then((r) => r.unwrap());
544
+ return this.get();
545
+ }
546
+ getErr() {
547
+ return this.promise.then((r) => r.getErr());
497
548
  }
549
+ /** @deprecated Use {@link AsyncRes.getErr}. */
498
550
  unwrapErr() {
499
- return this.promise.then((r) => r.unwrapErr());
551
+ return this.getErr();
552
+ }
553
+ getOr(fallback) {
554
+ return this.promise.then((r) => r.getOr(fallback));
500
555
  }
556
+ /** @deprecated Use {@link AsyncRes.getOr}. */
501
557
  unwrapOr(fallback) {
502
- return this.promise.then((r) => r.unwrapOr(fallback));
558
+ return this.getOr(fallback);
503
559
  }
560
+ getOrElse(f) {
561
+ return this.promise.then((r) => r.getOrElse(f));
562
+ }
563
+ /** @deprecated Use {@link AsyncRes.getOrElse}. */
504
564
  unwrapOrElse(f) {
505
- return this.promise.then((r) => r.unwrapOrElse(f));
565
+ return this.getOrElse(f);
506
566
  }
507
567
  getOrNull() {
508
568
  return this.promise.then((r) => r.getOrNull());
@@ -510,46 +570,59 @@ var AsyncRes = class AsyncRes {
510
570
  getOrUndefined() {
511
571
  return this.promise.then((r) => r.getOrUndefined());
512
572
  }
573
+ getOrThrow() {
574
+ return this.promise.then((r) => r.getOrThrow());
575
+ }
513
576
  };
514
577
  //#endregion
515
578
  //#region src/constructors.ts
579
+ function Ok(value) {
580
+ return okRes(value);
581
+ }
516
582
  /**
517
- * Construct a successful {@link Result}.
583
+ * Construct a failed {@link Result} carrying a **modeled** error.
518
584
  *
519
- * @typeParam T - the success value type.
520
- * @param value - the success value to wrap.
585
+ * @typeParam E - the modeled error type.
586
+ * @param error - the domain error to wrap.
521
587
  *
522
588
  * @example
523
589
  * ```ts
524
- * import { Ok } from "unthrown";
590
+ * import { Err } from "unthrown";
525
591
  *
526
- * Ok(2).map((n) => n + 1); // => Ok(3)
527
- * Ok(42).unwrap(); // => 42
592
+ * Err("not_found").map((n) => n + 1); // => Err("not_found") (map skipped)
593
+ * Err("not_found").getErr(); // => "not_found"
528
594
  * ```
529
595
  *
530
596
  * @category Constructors
531
597
  */
532
- function Ok(value) {
533
- return okRes(value);
598
+ function Err(error) {
599
+ return errRes(error);
600
+ }
601
+ function OkAsync(value) {
602
+ return Ok(value).toAsync();
534
603
  }
535
604
  /**
536
- * Construct a failed {@link Result} carrying a **modeled** error.
605
+ * Construct a failed {@link AsyncResult} carrying a **modeled** error — the
606
+ * pre-lifted form of {@link Err}, sparing you `Err(error).toAsync()`.
607
+ *
608
+ * @remarks
609
+ * The error-channel mirror of {@link OkAsync}; see it for the naming and the
610
+ * `AsyncResult.Err` companion alias.
537
611
  *
538
612
  * @typeParam E - the modeled error type.
539
613
  * @param error - the domain error to wrap.
540
614
  *
541
615
  * @example
542
616
  * ```ts
543
- * import { Err } from "unthrown";
617
+ * import { ErrAsync } from "unthrown";
544
618
  *
545
- * Err("not_found").map((n) => n + 1); // => Err("not_found") (map skipped)
546
- * Err("not_found").unwrapErr(); // => "not_found"
619
+ * ErrAsync("not_found"); // AsyncResult<never, string>
547
620
  * ```
548
621
  *
549
622
  * @category Constructors
550
623
  */
551
- function Err(error) {
552
- return errRes(error);
624
+ function ErrAsync(error) {
625
+ return Err(error).toAsync();
553
626
  }
554
627
  /**
555
628
  * Type guard: narrow a {@link Result} to its `Ok` variant, exposing `.value`.
@@ -718,9 +791,9 @@ function isDefectMarker(x) {
718
791
  * import { fromNullable } from "unthrown";
719
792
  *
720
793
  * const map = new Map([["a", 1]]);
721
- * fromNullable(map.get("a"), () => "absent").unwrapOr(0); // => 1
794
+ * fromNullable(map.get("a"), () => "absent").getOr(0); // => 1
722
795
  * fromNullable(map.get("z"), () => "absent"); // => Err("absent")
723
- * fromNullable(0, () => "absent").unwrapOr(-1); // => 0 (falsy but present)
796
+ * fromNullable(0, () => "absent").getOr(-1); // => 0 (falsy but present)
724
797
  * ```
725
798
  */
726
799
  function fromNullable(value, onAbsent) {
@@ -740,7 +813,7 @@ function fromNullable(value, onAbsent) {
740
813
  * `qualify`'s return is **subtracted** from `E`, never inferred into it. So a
741
814
  * `qualify` that returns *only* `defect(cause)` yields `E = never` (a Defect is
742
815
  * out-of-band and must not pollute the error channel); reach for
743
- * {@link fromSafePromise} when every failure is a Defect.
816
+ * {@link fromSafeThrowable} when every throw is a Defect.
744
817
  *
745
818
  * @typeParam A - the wrapped function's argument tuple.
746
819
  * @typeParam T - the wrapped function's return type.
@@ -764,7 +837,7 @@ function fromNullable(value, onAbsent) {
764
837
  * cause instanceof SyntaxError ? ("invalid_json" as const) : defect(cause),
765
838
  * );
766
839
  *
767
- * parse('{"ok":true}').unwrapOr(null); // => { ok: true }
840
+ * parse('{"ok":true}').getOr(null); // => { ok: true }
768
841
  * parse("nope"); // => Err("invalid_json")
769
842
  * ```
770
843
  */
@@ -779,6 +852,44 @@ function fromThrowable(fn, qualify) {
779
852
  };
780
853
  }
781
854
  /**
855
+ * Wrap a throwing synchronous function asserted **not** to fail in any modeled
856
+ * way: any throw becomes a `Defect`.
857
+ *
858
+ * @remarks
859
+ * The synchronous counterpart of {@link fromSafePromise}. Use it only when a
860
+ * throw genuinely indicates a bug rather than an anticipated outcome — the
861
+ * error channel is `never`, so there is nothing to triage; there is no
862
+ * `qualify`. When some throws *are* anticipated, reach for
863
+ * {@link fromThrowable} and triage them.
864
+ *
865
+ * @typeParam A - the wrapped function's argument tuple.
866
+ * @typeParam T - the wrapped function's return type.
867
+ * @param fn - the throwing function to wrap.
868
+ * @returns a function with the same arguments returning `Result<T, never>`.
869
+ *
870
+ * @category Interop
871
+ *
872
+ * @example
873
+ * ```ts
874
+ * import { fromSafeThrowable } from "unthrown";
875
+ *
876
+ * // A decode failure here is a bug (the row came from our own schema), so
877
+ * // every throw is a defect — no throwaway `(cause, defect) => defect(cause)`.
878
+ * const decode = fromSafeThrowable((row: Row) => userSchema.parse(row));
879
+ *
880
+ * decode(row); // => Result<User, never> — a throw becomes a Defect
881
+ * ```
882
+ */
883
+ function fromSafeThrowable(fn) {
884
+ return (...args) => {
885
+ try {
886
+ return Ok(fn(...args));
887
+ } catch (cause) {
888
+ return defectRes(cause);
889
+ }
890
+ };
891
+ }
892
+ /**
782
893
  * Wrap a `Promise` (or a thunk producing one) as an {@link AsyncResult}, forcing
783
894
  * every rejection to be triaged.
784
895
  *
@@ -826,7 +937,8 @@ function fromPromise(promise, qualify) {
826
937
  * @remarks
827
938
  * Use this only when a rejection genuinely indicates a bug rather than an
828
939
  * anticipated outcome — the error channel is `never`, so there is nothing to
829
- * triage. (`await`-ing still yields a `Result`; it never throws.)
940
+ * triage. (`await`-ing still yields a `Result`; it never throws.) The
941
+ * synchronous counterpart is {@link fromSafeThrowable}.
830
942
  *
831
943
  * @typeParam T - the resolved value type.
832
944
  * @param promise - the promise, or a thunk returning one.
@@ -837,7 +949,7 @@ function fromPromise(promise, qualify) {
837
949
  * ```ts
838
950
  * import { fromSafePromise } from "unthrown";
839
951
  *
840
- * (await fromSafePromise(Promise.resolve(3))).unwrap(); // => 3
952
+ * (await fromSafePromise(Promise.resolve(3))).get(); // => 3
841
953
  * // a rejection becomes a Defect (never a modeled Err):
842
954
  * await fromSafePromise(Promise.reject(new Error("boom"))); // => Defect(Error("boom"))
843
955
  * ```
@@ -911,7 +1023,7 @@ function foldRecord(results) {
911
1023
  * ```ts
912
1024
  * import { all, Ok, Err } from "unthrown";
913
1025
  *
914
- * all([Ok(1), Ok("a"), Ok(true)]).unwrap(); // => [1, "a", true] (typed [number, string, boolean])
1026
+ * all([Ok(1), Ok("a"), Ok(true)]).get(); // => [1, "a", true] (typed [number, string, boolean])
915
1027
  * all([Ok(1), Err("e"), Ok(3)]); // => Err("e") (short-circuits on the first Err)
916
1028
  * ```
917
1029
  */
@@ -934,7 +1046,7 @@ function all(results) {
934
1046
  * ```ts
935
1047
  * import { allFromDict, Ok, Err } from "unthrown";
936
1048
  *
937
- * allFromDict({ id: Ok(1), name: Ok("ada") }).unwrap(); // => { id: 1, name: "ada" }
1049
+ * allFromDict({ id: Ok(1), name: Ok("ada") }).get(); // => { id: 1, name: "ada" }
938
1050
  * allFromDict({ id: Ok(1), name: Err("missing") }); // => Err("missing")
939
1051
  * ```
940
1052
  */
@@ -958,7 +1070,7 @@ function allFromDict(results) {
958
1070
  * import { allAsync, fromSafePromise } from "unthrown";
959
1071
  *
960
1072
  * const both = allAsync([fromSafePromise(Promise.resolve(1)), fromSafePromise(Promise.resolve(2))]);
961
- * (await both).unwrap(); // => [1, 2]
1073
+ * (await both).get(); // => [1, 2]
962
1074
  * ```
963
1075
  */
964
1076
  function allAsync(results) {
@@ -982,7 +1094,7 @@ function allAsync(results) {
982
1094
  * a: fromSafePromise(Promise.resolve(1)),
983
1095
  * b: fromSafePromise(Promise.resolve("x")),
984
1096
  * });
985
- * (await both).unwrap(); // => { a: 1, b: "x" }
1097
+ * (await both).get(); // => { a: 1, b: "x" }
986
1098
  * ```
987
1099
  */
988
1100
  function allFromDictAsync(results) {
@@ -1001,8 +1113,9 @@ function allFromDictAsync(results) {
1001
1113
  * Companion object grouping the **`Result`-producing** entry points under a
1002
1114
  * single, discoverable namespace: {@link Result.Ok}, {@link Result.Err},
1003
1115
  * {@link Result.Do}, {@link Result.fromNullable}, {@link Result.fromThrowable},
1004
- * {@link Result.all}, {@link Result.allFromDict}, {@link Result.isOk},
1005
- * {@link Result.isErr}, {@link Result.isDefect}, {@link Result.isResult}.
1116
+ * {@link Result.fromSafeThrowable}, {@link Result.all},
1117
+ * {@link Result.allFromDict}, {@link Result.isOk}, {@link Result.isErr},
1118
+ * {@link Result.isDefect}, {@link Result.isResult}.
1006
1119
  *
1007
1120
  * @remarks
1008
1121
  * Purely additive sugar — each member **is** the corresponding free function.
@@ -1019,7 +1132,7 @@ function allFromDictAsync(results) {
1019
1132
  * @example
1020
1133
  * ```ts
1021
1134
  * import { Result } from "unthrown";
1022
- * Result.Ok(1).flatMap((n) => Result.Ok(n + 1)).unwrap(); // => 2
1135
+ * Result.Ok(1).flatMap((n) => Result.Ok(n + 1)).get(); // => 2
1023
1136
  * ```
1024
1137
  */
1025
1138
  const Result = {
@@ -1028,6 +1141,7 @@ const Result = {
1028
1141
  Do,
1029
1142
  fromNullable,
1030
1143
  fromThrowable,
1144
+ fromSafeThrowable,
1031
1145
  all,
1032
1146
  allFromDict,
1033
1147
  isOk,
@@ -1037,18 +1151,20 @@ const Result = {
1037
1151
  };
1038
1152
  /**
1039
1153
  * Companion object grouping the **`AsyncResult`-producing** entry points under
1040
- * the matching namespace: {@link AsyncResult.fromPromise},
1041
- * {@link AsyncResult.fromSafePromise}, {@link AsyncResult.all},
1042
- * {@link AsyncResult.allFromDict}.
1154
+ * the matching namespace: {@link AsyncResult.Ok}, {@link AsyncResult.Err},
1155
+ * {@link AsyncResult.fromPromise}, {@link AsyncResult.fromSafePromise},
1156
+ * {@link AsyncResult.all}, {@link AsyncResult.allFromDict}.
1043
1157
  *
1044
1158
  * @remarks
1045
1159
  * The async sibling of {@link Result}. Statics are grouped by what they
1046
- * **return**, so `fromPromise`/`fromSafePromise` and the async aggregates sit
1047
- * here rather than on {@link Result}; the namespace already conveys "async", so
1048
- * the aggregates drop the `Async` suffix (`AsyncResult.all` is the free function
1049
- * `allAsync`; `AsyncResult.allFromDict` is `allFromDictAsync`). Like
1050
- * {@link Result}, the free functions remain the primary, tree-shakeable API; the
1051
- * value `AsyncResult` and the type {@link AsyncResult} share one name.
1160
+ * **return**, so the pre-lifted constructors, `fromPromise`/`fromSafePromise`,
1161
+ * and the async aggregates sit here rather than on {@link Result}; the namespace
1162
+ * already conveys "async", so the members drop the `Async` suffix their free
1163
+ * functions carry (`AsyncResult.Ok` is `OkAsync`; `AsyncResult.Err` is
1164
+ * `ErrAsync`; `AsyncResult.all` is `allAsync`; `AsyncResult.allFromDict` is
1165
+ * `allFromDictAsync`). Like {@link Result}, the free functions remain the
1166
+ * primary, tree-shakeable API; the value `AsyncResult` and the type
1167
+ * {@link AsyncResult} share one name.
1052
1168
  *
1053
1169
  * @category Facade
1054
1170
  *
@@ -1056,10 +1172,12 @@ const Result = {
1056
1172
  * ```ts
1057
1173
  * import { AsyncResult } from "unthrown";
1058
1174
  * const user = await AsyncResult.fromPromise(fetchUser(id), (c, defect) => defect(c));
1059
- * user.unwrap(); // => the fetched user (on success)
1175
+ * user.get(); // => the fetched user (on success)
1060
1176
  * ```
1061
1177
  */
1062
1178
  const AsyncResult = {
1179
+ Ok: OkAsync,
1180
+ Err: ErrAsync,
1063
1181
  fromPromise,
1064
1182
  fromSafePromise,
1065
1183
  all: allAsync,
@@ -1151,7 +1269,9 @@ function matchTags(result, handlers) {
1151
1269
  exports.AsyncResult = AsyncResult;
1152
1270
  exports.Do = Do;
1153
1271
  exports.Err = Err;
1272
+ exports.ErrAsync = ErrAsync;
1154
1273
  exports.Ok = Ok;
1274
+ exports.OkAsync = OkAsync;
1155
1275
  exports.Result = Result;
1156
1276
  exports.TaggedError = TaggedError;
1157
1277
  exports.UnwrapError = UnwrapError;
@@ -1162,6 +1282,7 @@ exports.allFromDictAsync = allFromDictAsync;
1162
1282
  exports.fromNullable = fromNullable;
1163
1283
  exports.fromPromise = fromPromise;
1164
1284
  exports.fromSafePromise = fromSafePromise;
1285
+ exports.fromSafeThrowable = fromSafeThrowable;
1165
1286
  exports.fromThrowable = fromThrowable;
1166
1287
  exports.isDefect = isDefect;
1167
1288
  exports.isErr = isErr;