unthrown 3.1.0 → 4.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/dist/index.cjs +221 -51
- package/dist/index.d.cts +336 -71
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +336 -71
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +219 -52
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
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 `
|
|
5
|
-
* wrong on a *modeled* result — `
|
|
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,14 +14,19 @@ 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
|
+
* `get()` and `getErr()` are type-gated (`this: Result<T, never>` /
|
|
18
|
+
* `Result<never, E>`), so the wrong-variant branch that throws this is
|
|
19
|
+
* unreachable through well-typed code — it remains only as a defensive guard
|
|
20
|
+
* against unsound runtime misuse (e.g. an `as` cast past the gate).
|
|
21
|
+
*
|
|
17
22
|
* @typeParam E - the type of the {@link UnwrapError.error} it carries.
|
|
18
23
|
*
|
|
19
24
|
* @category Errors
|
|
20
25
|
*/
|
|
21
26
|
var UnwrapError = class extends Error {
|
|
22
27
|
/**
|
|
23
|
-
* The offending value: the `Err` error for `
|
|
24
|
-
* `
|
|
28
|
+
* The offending value: the `Err` error for `get()`, or the `Ok` value for
|
|
29
|
+
* `getErr()`.
|
|
25
30
|
*/
|
|
26
31
|
error;
|
|
27
32
|
constructor(error) {
|
|
@@ -109,7 +114,7 @@ var Res = class {
|
|
|
109
114
|
return defectRes(cause);
|
|
110
115
|
}
|
|
111
116
|
}
|
|
112
|
-
|
|
117
|
+
flatMapErr(f) {
|
|
113
118
|
if (this.tag !== "Err") return passThrough(this);
|
|
114
119
|
try {
|
|
115
120
|
return f(this.error);
|
|
@@ -117,7 +122,11 @@ var Res = class {
|
|
|
117
122
|
return defectRes(cause);
|
|
118
123
|
}
|
|
119
124
|
}
|
|
120
|
-
|
|
125
|
+
/** @deprecated Use {@link Res.flatMapErr}. */
|
|
126
|
+
orElse(f) {
|
|
127
|
+
return this.flatMapErr(f);
|
|
128
|
+
}
|
|
129
|
+
recoverErr(f) {
|
|
121
130
|
if (this.tag !== "Err") return passThrough(this);
|
|
122
131
|
try {
|
|
123
132
|
return okRes(f(this.error));
|
|
@@ -125,6 +134,10 @@ var Res = class {
|
|
|
125
134
|
return defectRes(cause);
|
|
126
135
|
}
|
|
127
136
|
}
|
|
137
|
+
/** @deprecated Use {@link Res.recoverErr}. */
|
|
138
|
+
recover(f) {
|
|
139
|
+
return this.recoverErr(f);
|
|
140
|
+
}
|
|
128
141
|
tapErr(f) {
|
|
129
142
|
if (this.tag !== "Err") return this;
|
|
130
143
|
try {
|
|
@@ -167,30 +180,46 @@ var Res = class {
|
|
|
167
180
|
case "Defect": return cases.defect(this.cause);
|
|
168
181
|
}
|
|
169
182
|
}
|
|
170
|
-
|
|
183
|
+
get() {
|
|
171
184
|
switch (this.tag) {
|
|
172
185
|
case "Ok": return this.value;
|
|
173
186
|
case "Err": throw new UnwrapError(this.error);
|
|
174
187
|
case "Defect": throw this.cause;
|
|
175
188
|
}
|
|
176
189
|
}
|
|
177
|
-
|
|
190
|
+
/** @deprecated Use {@link Res.get}. */
|
|
191
|
+
unwrap() {
|
|
192
|
+
return this.get();
|
|
193
|
+
}
|
|
194
|
+
getErr() {
|
|
178
195
|
switch (this.tag) {
|
|
179
196
|
case "Err": return this.error;
|
|
180
197
|
case "Ok": throw new UnwrapError(this.value);
|
|
181
198
|
case "Defect": throw this.cause;
|
|
182
199
|
}
|
|
183
200
|
}
|
|
184
|
-
|
|
201
|
+
/** @deprecated Use {@link Res.getErr}. */
|
|
202
|
+
unwrapErr() {
|
|
203
|
+
return this.getErr();
|
|
204
|
+
}
|
|
205
|
+
getOr(fallback) {
|
|
185
206
|
if (this.tag === "Ok") return this.value;
|
|
186
207
|
if (this.tag === "Defect") throw this.cause;
|
|
187
208
|
return fallback;
|
|
188
209
|
}
|
|
189
|
-
|
|
210
|
+
/** @deprecated Use {@link Res.getOr}. */
|
|
211
|
+
unwrapOr(fallback) {
|
|
212
|
+
return this.getOr(fallback);
|
|
213
|
+
}
|
|
214
|
+
getOrElse(f) {
|
|
190
215
|
if (this.tag === "Ok") return this.value;
|
|
191
216
|
if (this.tag === "Defect") throw this.cause;
|
|
192
217
|
return f(this.error);
|
|
193
218
|
}
|
|
219
|
+
/** @deprecated Use {@link Res.getOrElse}. */
|
|
220
|
+
unwrapOrElse(f) {
|
|
221
|
+
return this.getOrElse(f);
|
|
222
|
+
}
|
|
194
223
|
getOrNull() {
|
|
195
224
|
if (this.tag === "Ok") return this.value;
|
|
196
225
|
if (this.tag === "Defect") throw this.cause;
|
|
@@ -200,6 +229,11 @@ var Res = class {
|
|
|
200
229
|
if (this.tag === "Ok") return this.value;
|
|
201
230
|
if (this.tag === "Defect") throw this.cause;
|
|
202
231
|
}
|
|
232
|
+
getOrThrow() {
|
|
233
|
+
if (this.tag === "Ok") return this.value;
|
|
234
|
+
if (this.tag === "Defect") throw this.cause;
|
|
235
|
+
throw this.error;
|
|
236
|
+
}
|
|
203
237
|
isOk() {
|
|
204
238
|
return this.tag === "Ok";
|
|
205
239
|
}
|
|
@@ -421,7 +455,7 @@ var AsyncRes = class AsyncRes {
|
|
|
421
455
|
}
|
|
422
456
|
}));
|
|
423
457
|
}
|
|
424
|
-
|
|
458
|
+
flatMapErr(f) {
|
|
425
459
|
return new AsyncRes(this.promise.then(async (r) => {
|
|
426
460
|
if (r.tag !== "Err") return passThrough(r);
|
|
427
461
|
try {
|
|
@@ -431,7 +465,11 @@ var AsyncRes = class AsyncRes {
|
|
|
431
465
|
}
|
|
432
466
|
}));
|
|
433
467
|
}
|
|
434
|
-
|
|
468
|
+
/** @deprecated Use {@link AsyncRes.flatMapErr}. */
|
|
469
|
+
orElse(f) {
|
|
470
|
+
return this.flatMapErr(f);
|
|
471
|
+
}
|
|
472
|
+
recoverErr(f) {
|
|
435
473
|
return new AsyncRes(this.promise.then((r) => {
|
|
436
474
|
if (r.tag !== "Err") return passThrough(r);
|
|
437
475
|
try {
|
|
@@ -441,6 +479,10 @@ var AsyncRes = class AsyncRes {
|
|
|
441
479
|
}
|
|
442
480
|
}));
|
|
443
481
|
}
|
|
482
|
+
/** @deprecated Use {@link AsyncRes.recoverErr}. */
|
|
483
|
+
recover(f) {
|
|
484
|
+
return this.recoverErr(f);
|
|
485
|
+
}
|
|
444
486
|
tapErr(f) {
|
|
445
487
|
return new AsyncRes(this.promise.then((r) => {
|
|
446
488
|
if (r.tag !== "Err") return r;
|
|
@@ -487,17 +529,33 @@ var AsyncRes = class AsyncRes {
|
|
|
487
529
|
match(cases) {
|
|
488
530
|
return this.promise.then((r) => r.match(cases));
|
|
489
531
|
}
|
|
532
|
+
get() {
|
|
533
|
+
return this.promise.then((r) => r.get());
|
|
534
|
+
}
|
|
535
|
+
/** @deprecated Use {@link AsyncRes.get}. */
|
|
490
536
|
unwrap() {
|
|
491
|
-
return this.
|
|
537
|
+
return this.get();
|
|
538
|
+
}
|
|
539
|
+
getErr() {
|
|
540
|
+
return this.promise.then((r) => r.getErr());
|
|
492
541
|
}
|
|
542
|
+
/** @deprecated Use {@link AsyncRes.getErr}. */
|
|
493
543
|
unwrapErr() {
|
|
494
|
-
return this.
|
|
544
|
+
return this.getErr();
|
|
545
|
+
}
|
|
546
|
+
getOr(fallback) {
|
|
547
|
+
return this.promise.then((r) => r.getOr(fallback));
|
|
495
548
|
}
|
|
549
|
+
/** @deprecated Use {@link AsyncRes.getOr}. */
|
|
496
550
|
unwrapOr(fallback) {
|
|
497
|
-
return this.
|
|
551
|
+
return this.getOr(fallback);
|
|
498
552
|
}
|
|
553
|
+
getOrElse(f) {
|
|
554
|
+
return this.promise.then((r) => r.getOrElse(f));
|
|
555
|
+
}
|
|
556
|
+
/** @deprecated Use {@link AsyncRes.getOrElse}. */
|
|
499
557
|
unwrapOrElse(f) {
|
|
500
|
-
return this.
|
|
558
|
+
return this.getOrElse(f);
|
|
501
559
|
}
|
|
502
560
|
getOrNull() {
|
|
503
561
|
return this.promise.then((r) => r.getOrNull());
|
|
@@ -505,6 +563,9 @@ var AsyncRes = class AsyncRes {
|
|
|
505
563
|
getOrUndefined() {
|
|
506
564
|
return this.promise.then((r) => r.getOrUndefined());
|
|
507
565
|
}
|
|
566
|
+
getOrThrow() {
|
|
567
|
+
return this.promise.then((r) => r.getOrThrow());
|
|
568
|
+
}
|
|
508
569
|
};
|
|
509
570
|
//#endregion
|
|
510
571
|
//#region src/constructors.ts
|
|
@@ -519,7 +580,7 @@ var AsyncRes = class AsyncRes {
|
|
|
519
580
|
* import { Ok } from "unthrown";
|
|
520
581
|
*
|
|
521
582
|
* Ok(2).map((n) => n + 1); // => Ok(3)
|
|
522
|
-
* Ok(42).
|
|
583
|
+
* Ok(42).get(); // => 42
|
|
523
584
|
* ```
|
|
524
585
|
*
|
|
525
586
|
* @category Constructors
|
|
@@ -538,7 +599,7 @@ function Ok(value) {
|
|
|
538
599
|
* import { Err } from "unthrown";
|
|
539
600
|
*
|
|
540
601
|
* Err("not_found").map((n) => n + 1); // => Err("not_found") (map skipped)
|
|
541
|
-
* Err("not_found").
|
|
602
|
+
* Err("not_found").getErr(); // => "not_found"
|
|
542
603
|
* ```
|
|
543
604
|
*
|
|
544
605
|
* @category Constructors
|
|
@@ -547,6 +608,58 @@ function Err(error) {
|
|
|
547
608
|
return errRes(error);
|
|
548
609
|
}
|
|
549
610
|
/**
|
|
611
|
+
* Construct a successful {@link AsyncResult} from a pure value — the pre-lifted
|
|
612
|
+
* form of {@link Ok}, sparing you `Ok(value).toAsync()`.
|
|
613
|
+
*
|
|
614
|
+
* @remarks
|
|
615
|
+
* Reach for this on the synchronous/early branch of an `AsyncResult`-returning
|
|
616
|
+
* function, so both branches share one return type without a trailing
|
|
617
|
+
* `.toAsync()`. Named with the `Async` suffix the async free functions carry
|
|
618
|
+
* (`allAsync`, `allFromDictAsync`); the {@link AsyncResult} companion aliases it
|
|
619
|
+
* as `AsyncResult.Ok` (the namespace already says "async", so the suffix drops).
|
|
620
|
+
*
|
|
621
|
+
* @typeParam T - the success value type.
|
|
622
|
+
* @param value - the success value to wrap.
|
|
623
|
+
*
|
|
624
|
+
* @example
|
|
625
|
+
* ```ts
|
|
626
|
+
* import { OkAsync, type AsyncResult } from "unthrown";
|
|
627
|
+
*
|
|
628
|
+
* function loadItems(ids: string[]): AsyncResult<Item[], never> {
|
|
629
|
+
* if (ids.length === 0) return OkAsync([]); // no more Ok([]).toAsync()
|
|
630
|
+
* return itemRepository.load(ids);
|
|
631
|
+
* }
|
|
632
|
+
* ```
|
|
633
|
+
*
|
|
634
|
+
* @category Constructors
|
|
635
|
+
*/
|
|
636
|
+
function OkAsync(value) {
|
|
637
|
+
return Ok(value).toAsync();
|
|
638
|
+
}
|
|
639
|
+
/**
|
|
640
|
+
* Construct a failed {@link AsyncResult} carrying a **modeled** error — the
|
|
641
|
+
* pre-lifted form of {@link Err}, sparing you `Err(error).toAsync()`.
|
|
642
|
+
*
|
|
643
|
+
* @remarks
|
|
644
|
+
* The error-channel mirror of {@link OkAsync}; see it for the naming and the
|
|
645
|
+
* `AsyncResult.Err` companion alias.
|
|
646
|
+
*
|
|
647
|
+
* @typeParam E - the modeled error type.
|
|
648
|
+
* @param error - the domain error to wrap.
|
|
649
|
+
*
|
|
650
|
+
* @example
|
|
651
|
+
* ```ts
|
|
652
|
+
* import { ErrAsync } from "unthrown";
|
|
653
|
+
*
|
|
654
|
+
* ErrAsync("not_found"); // AsyncResult<never, string>
|
|
655
|
+
* ```
|
|
656
|
+
*
|
|
657
|
+
* @category Constructors
|
|
658
|
+
*/
|
|
659
|
+
function ErrAsync(error) {
|
|
660
|
+
return Err(error).toAsync();
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
550
663
|
* Type guard: narrow a {@link Result} to its `Ok` variant, exposing `.value`.
|
|
551
664
|
*
|
|
552
665
|
* @returns `true` when `r` is `Ok`.
|
|
@@ -713,9 +826,9 @@ function isDefectMarker(x) {
|
|
|
713
826
|
* import { fromNullable } from "unthrown";
|
|
714
827
|
*
|
|
715
828
|
* const map = new Map([["a", 1]]);
|
|
716
|
-
* fromNullable(map.get("a"), () => "absent").
|
|
829
|
+
* fromNullable(map.get("a"), () => "absent").getOr(0); // => 1
|
|
717
830
|
* fromNullable(map.get("z"), () => "absent"); // => Err("absent")
|
|
718
|
-
* fromNullable(0, () => "absent").
|
|
831
|
+
* fromNullable(0, () => "absent").getOr(-1); // => 0 (falsy but present)
|
|
719
832
|
* ```
|
|
720
833
|
*/
|
|
721
834
|
function fromNullable(value, onAbsent) {
|
|
@@ -735,7 +848,7 @@ function fromNullable(value, onAbsent) {
|
|
|
735
848
|
* `qualify`'s return is **subtracted** from `E`, never inferred into it. So a
|
|
736
849
|
* `qualify` that returns *only* `defect(cause)` yields `E = never` (a Defect is
|
|
737
850
|
* out-of-band and must not pollute the error channel); reach for
|
|
738
|
-
* {@link
|
|
851
|
+
* {@link fromSafeThrowable} when every throw is a Defect.
|
|
739
852
|
*
|
|
740
853
|
* @typeParam A - the wrapped function's argument tuple.
|
|
741
854
|
* @typeParam T - the wrapped function's return type.
|
|
@@ -759,7 +872,7 @@ function fromNullable(value, onAbsent) {
|
|
|
759
872
|
* cause instanceof SyntaxError ? ("invalid_json" as const) : defect(cause),
|
|
760
873
|
* );
|
|
761
874
|
*
|
|
762
|
-
* parse('{"ok":true}').
|
|
875
|
+
* parse('{"ok":true}').getOr(null); // => { ok: true }
|
|
763
876
|
* parse("nope"); // => Err("invalid_json")
|
|
764
877
|
* ```
|
|
765
878
|
*/
|
|
@@ -774,6 +887,44 @@ function fromThrowable(fn, qualify) {
|
|
|
774
887
|
};
|
|
775
888
|
}
|
|
776
889
|
/**
|
|
890
|
+
* Wrap a throwing synchronous function asserted **not** to fail in any modeled
|
|
891
|
+
* way: any throw becomes a `Defect`.
|
|
892
|
+
*
|
|
893
|
+
* @remarks
|
|
894
|
+
* The synchronous counterpart of {@link fromSafePromise}. Use it only when a
|
|
895
|
+
* throw genuinely indicates a bug rather than an anticipated outcome — the
|
|
896
|
+
* error channel is `never`, so there is nothing to triage; there is no
|
|
897
|
+
* `qualify`. When some throws *are* anticipated, reach for
|
|
898
|
+
* {@link fromThrowable} and triage them.
|
|
899
|
+
*
|
|
900
|
+
* @typeParam A - the wrapped function's argument tuple.
|
|
901
|
+
* @typeParam T - the wrapped function's return type.
|
|
902
|
+
* @param fn - the throwing function to wrap.
|
|
903
|
+
* @returns a function with the same arguments returning `Result<T, never>`.
|
|
904
|
+
*
|
|
905
|
+
* @category Interop
|
|
906
|
+
*
|
|
907
|
+
* @example
|
|
908
|
+
* ```ts
|
|
909
|
+
* import { fromSafeThrowable } from "unthrown";
|
|
910
|
+
*
|
|
911
|
+
* // A decode failure here is a bug (the row came from our own schema), so
|
|
912
|
+
* // every throw is a defect — no throwaway `(cause, defect) => defect(cause)`.
|
|
913
|
+
* const decode = fromSafeThrowable((row: Row) => userSchema.parse(row));
|
|
914
|
+
*
|
|
915
|
+
* decode(row); // => Result<User, never> — a throw becomes a Defect
|
|
916
|
+
* ```
|
|
917
|
+
*/
|
|
918
|
+
function fromSafeThrowable(fn) {
|
|
919
|
+
return (...args) => {
|
|
920
|
+
try {
|
|
921
|
+
return Ok(fn(...args));
|
|
922
|
+
} catch (cause) {
|
|
923
|
+
return defectRes(cause);
|
|
924
|
+
}
|
|
925
|
+
};
|
|
926
|
+
}
|
|
927
|
+
/**
|
|
777
928
|
* Wrap a `Promise` (or a thunk producing one) as an {@link AsyncResult}, forcing
|
|
778
929
|
* every rejection to be triaged.
|
|
779
930
|
*
|
|
@@ -806,8 +957,8 @@ function fromThrowable(fn, qualify) {
|
|
|
806
957
|
* cause instanceof NotFoundError ? ("not_found" as const) : defect(cause),
|
|
807
958
|
* );
|
|
808
959
|
*
|
|
809
|
-
* user.
|
|
810
|
-
* // when fetchUser rejects with NotFoundError:
|
|
960
|
+
* if (user.isOk()) user.value; // => the fetched user
|
|
961
|
+
* // when fetchUser rejects with NotFoundError: user is Err("not_found")
|
|
811
962
|
* ```
|
|
812
963
|
*/
|
|
813
964
|
function fromPromise(promise, qualify) {
|
|
@@ -821,7 +972,8 @@ function fromPromise(promise, qualify) {
|
|
|
821
972
|
* @remarks
|
|
822
973
|
* Use this only when a rejection genuinely indicates a bug rather than an
|
|
823
974
|
* anticipated outcome — the error channel is `never`, so there is nothing to
|
|
824
|
-
* triage. (`await`-ing still yields a `Result`; it never throws.)
|
|
975
|
+
* triage. (`await`-ing still yields a `Result`; it never throws.) The
|
|
976
|
+
* synchronous counterpart is {@link fromSafeThrowable}.
|
|
825
977
|
*
|
|
826
978
|
* @typeParam T - the resolved value type.
|
|
827
979
|
* @param promise - the promise, or a thunk returning one.
|
|
@@ -832,7 +984,7 @@ function fromPromise(promise, qualify) {
|
|
|
832
984
|
* ```ts
|
|
833
985
|
* import { fromSafePromise } from "unthrown";
|
|
834
986
|
*
|
|
835
|
-
* (await fromSafePromise(Promise.resolve(3))).
|
|
987
|
+
* (await fromSafePromise(Promise.resolve(3))).get(); // => 3
|
|
836
988
|
* // a rejection becomes a Defect (never a modeled Err):
|
|
837
989
|
* await fromSafePromise(Promise.reject(new Error("boom"))); // => Defect(Error("boom"))
|
|
838
990
|
* ```
|
|
@@ -906,7 +1058,7 @@ function foldRecord(results) {
|
|
|
906
1058
|
* ```ts
|
|
907
1059
|
* import { all, Ok, Err } from "unthrown";
|
|
908
1060
|
*
|
|
909
|
-
* all([Ok(1), Ok("a"), Ok(true)]).
|
|
1061
|
+
* all([Ok(1), Ok("a"), Ok(true)]).get(); // => [1, "a", true] (typed [number, string, boolean])
|
|
910
1062
|
* all([Ok(1), Err("e"), Ok(3)]); // => Err("e") (short-circuits on the first Err)
|
|
911
1063
|
* ```
|
|
912
1064
|
*/
|
|
@@ -929,7 +1081,7 @@ function all(results) {
|
|
|
929
1081
|
* ```ts
|
|
930
1082
|
* import { allFromDict, Ok, Err } from "unthrown";
|
|
931
1083
|
*
|
|
932
|
-
* allFromDict({ id: Ok(1), name: Ok("ada") }).
|
|
1084
|
+
* allFromDict({ id: Ok(1), name: Ok("ada") }).get(); // => { id: 1, name: "ada" }
|
|
933
1085
|
* allFromDict({ id: Ok(1), name: Err("missing") }); // => Err("missing")
|
|
934
1086
|
* ```
|
|
935
1087
|
*/
|
|
@@ -953,7 +1105,7 @@ function allFromDict(results) {
|
|
|
953
1105
|
* import { allAsync, fromSafePromise } from "unthrown";
|
|
954
1106
|
*
|
|
955
1107
|
* const both = allAsync([fromSafePromise(Promise.resolve(1)), fromSafePromise(Promise.resolve(2))]);
|
|
956
|
-
* (await both).
|
|
1108
|
+
* (await both).get(); // => [1, 2]
|
|
957
1109
|
* ```
|
|
958
1110
|
*/
|
|
959
1111
|
function allAsync(results) {
|
|
@@ -977,7 +1129,7 @@ function allAsync(results) {
|
|
|
977
1129
|
* a: fromSafePromise(Promise.resolve(1)),
|
|
978
1130
|
* b: fromSafePromise(Promise.resolve("x")),
|
|
979
1131
|
* });
|
|
980
|
-
* (await both).
|
|
1132
|
+
* (await both).get(); // => { a: 1, b: "x" }
|
|
981
1133
|
* ```
|
|
982
1134
|
*/
|
|
983
1135
|
function allFromDictAsync(results) {
|
|
@@ -996,8 +1148,9 @@ function allFromDictAsync(results) {
|
|
|
996
1148
|
* Companion object grouping the **`Result`-producing** entry points under a
|
|
997
1149
|
* single, discoverable namespace: {@link Result.Ok}, {@link Result.Err},
|
|
998
1150
|
* {@link Result.Do}, {@link Result.fromNullable}, {@link Result.fromThrowable},
|
|
999
|
-
* {@link Result.
|
|
1000
|
-
* {@link Result.
|
|
1151
|
+
* {@link Result.fromSafeThrowable}, {@link Result.all},
|
|
1152
|
+
* {@link Result.allFromDict}, {@link Result.isOk}, {@link Result.isErr},
|
|
1153
|
+
* {@link Result.isDefect}, {@link Result.isResult}.
|
|
1001
1154
|
*
|
|
1002
1155
|
* @remarks
|
|
1003
1156
|
* Purely additive sugar — each member **is** the corresponding free function.
|
|
@@ -1014,7 +1167,7 @@ function allFromDictAsync(results) {
|
|
|
1014
1167
|
* @example
|
|
1015
1168
|
* ```ts
|
|
1016
1169
|
* import { Result } from "unthrown";
|
|
1017
|
-
* Result.Ok(1).flatMap((n) => Result.Ok(n + 1)).
|
|
1170
|
+
* Result.Ok(1).flatMap((n) => Result.Ok(n + 1)).get(); // => 2
|
|
1018
1171
|
* ```
|
|
1019
1172
|
*/
|
|
1020
1173
|
const Result = {
|
|
@@ -1023,6 +1176,7 @@ const Result = {
|
|
|
1023
1176
|
Do,
|
|
1024
1177
|
fromNullable,
|
|
1025
1178
|
fromThrowable,
|
|
1179
|
+
fromSafeThrowable,
|
|
1026
1180
|
all,
|
|
1027
1181
|
allFromDict,
|
|
1028
1182
|
isOk,
|
|
@@ -1032,18 +1186,20 @@ const Result = {
|
|
|
1032
1186
|
};
|
|
1033
1187
|
/**
|
|
1034
1188
|
* Companion object grouping the **`AsyncResult`-producing** entry points under
|
|
1035
|
-
* the matching namespace: {@link AsyncResult.
|
|
1036
|
-
* {@link AsyncResult.
|
|
1037
|
-
* {@link AsyncResult.allFromDict}.
|
|
1189
|
+
* the matching namespace: {@link AsyncResult.Ok}, {@link AsyncResult.Err},
|
|
1190
|
+
* {@link AsyncResult.fromPromise}, {@link AsyncResult.fromSafePromise},
|
|
1191
|
+
* {@link AsyncResult.all}, {@link AsyncResult.allFromDict}.
|
|
1038
1192
|
*
|
|
1039
1193
|
* @remarks
|
|
1040
1194
|
* The async sibling of {@link Result}. Statics are grouped by what they
|
|
1041
|
-
* **return**, so `fromPromise`/`fromSafePromise
|
|
1042
|
-
* here rather than on {@link Result}; the namespace
|
|
1043
|
-
* the
|
|
1044
|
-
*
|
|
1045
|
-
*
|
|
1046
|
-
*
|
|
1195
|
+
* **return**, so the pre-lifted constructors, `fromPromise`/`fromSafePromise`,
|
|
1196
|
+
* and the async aggregates sit here rather than on {@link Result}; the namespace
|
|
1197
|
+
* already conveys "async", so the members drop the `Async` suffix their free
|
|
1198
|
+
* functions carry (`AsyncResult.Ok` is `OkAsync`; `AsyncResult.Err` is
|
|
1199
|
+
* `ErrAsync`; `AsyncResult.all` is `allAsync`; `AsyncResult.allFromDict` is
|
|
1200
|
+
* `allFromDictAsync`). Like {@link Result}, the free functions remain the
|
|
1201
|
+
* primary, tree-shakeable API; the value `AsyncResult` and the type
|
|
1202
|
+
* {@link AsyncResult} share one name.
|
|
1047
1203
|
*
|
|
1048
1204
|
* @category Facade
|
|
1049
1205
|
*
|
|
@@ -1051,10 +1207,12 @@ const Result = {
|
|
|
1051
1207
|
* ```ts
|
|
1052
1208
|
* import { AsyncResult } from "unthrown";
|
|
1053
1209
|
* const user = await AsyncResult.fromPromise(fetchUser(id), (c, defect) => defect(c));
|
|
1054
|
-
* user.
|
|
1210
|
+
* user.get(); // => the fetched user (on success)
|
|
1055
1211
|
* ```
|
|
1056
1212
|
*/
|
|
1057
1213
|
const AsyncResult = {
|
|
1214
|
+
Ok: OkAsync,
|
|
1215
|
+
Err: ErrAsync,
|
|
1058
1216
|
fromPromise,
|
|
1059
1217
|
fromSafePromise,
|
|
1060
1218
|
all: allAsync,
|
|
@@ -1068,8 +1226,13 @@ const AsyncResult = {
|
|
|
1068
1226
|
*
|
|
1069
1227
|
* @remarks
|
|
1070
1228
|
* Extend the returned class to declare a concrete error. Supply the payload with
|
|
1071
|
-
* an instantiation expression; omit it for a payload-less error.
|
|
1072
|
-
*
|
|
1229
|
+
* an instantiation expression; omit it for a payload-less error. The `message`
|
|
1230
|
+
* is **not** a payload field — it is the human string owned by `Error`, not
|
|
1231
|
+
* structured data, so it is reserved. Define it once per subclass the standard
|
|
1232
|
+
* way, `override message = "…"` (it may interpolate the payload via `this`,
|
|
1233
|
+
* which the base populates before the subclass field initialiser runs); a
|
|
1234
|
+
* payload `message` is rejected at compile time, so contextual detail lives in
|
|
1235
|
+
* typed fields, never baked into per-call prose. The `_tag` always reflects
|
|
1073
1236
|
* `tag` and cannot be overridden by the payload. `name` is likewise reserved —
|
|
1074
1237
|
* it is the display label (set it with `options.name`); a payload `name` is
|
|
1075
1238
|
* rejected at compile time (and excluded from the instance type), so it can't
|
|
@@ -1084,11 +1247,14 @@ const AsyncResult = {
|
|
|
1084
1247
|
* ```ts
|
|
1085
1248
|
* class RetryableError extends TaggedError("@my-lib/RetryableError", {
|
|
1086
1249
|
* name: "RetryableError",
|
|
1087
|
-
* })
|
|
1088
|
-
*
|
|
1089
|
-
*
|
|
1090
|
-
*
|
|
1091
|
-
* e
|
|
1250
|
+
* }) {
|
|
1251
|
+
* override message = "operation failed; safe to retry";
|
|
1252
|
+
* }
|
|
1253
|
+
*
|
|
1254
|
+
* const e = new RetryableError();
|
|
1255
|
+
* e._tag; // "@my-lib/RetryableError" — namespaced discriminant
|
|
1256
|
+
* e.name; // "RetryableError" — clean display name
|
|
1257
|
+
* e.message; // "operation failed; safe to retry" — the standard Error.message
|
|
1092
1258
|
* ```
|
|
1093
1259
|
*
|
|
1094
1260
|
* @typeParam Tag - the string literal discriminant.
|
|
@@ -1112,10 +1278,11 @@ function TaggedError(tag, options) {
|
|
|
1112
1278
|
class TaggedErrorBase extends Error {
|
|
1113
1279
|
_tag;
|
|
1114
1280
|
constructor(props) {
|
|
1115
|
-
super(
|
|
1281
|
+
super();
|
|
1116
1282
|
if (props) Object.assign(this, props);
|
|
1117
1283
|
this._tag = tag;
|
|
1118
1284
|
this.name = displayName;
|
|
1285
|
+
delete this.message;
|
|
1119
1286
|
Object.setPrototypeOf(this, new.target.prototype);
|
|
1120
1287
|
}
|
|
1121
1288
|
}
|
|
@@ -1137,7 +1304,9 @@ function matchTags(result, handlers) {
|
|
|
1137
1304
|
exports.AsyncResult = AsyncResult;
|
|
1138
1305
|
exports.Do = Do;
|
|
1139
1306
|
exports.Err = Err;
|
|
1307
|
+
exports.ErrAsync = ErrAsync;
|
|
1140
1308
|
exports.Ok = Ok;
|
|
1309
|
+
exports.OkAsync = OkAsync;
|
|
1141
1310
|
exports.Result = Result;
|
|
1142
1311
|
exports.TaggedError = TaggedError;
|
|
1143
1312
|
exports.UnwrapError = UnwrapError;
|
|
@@ -1148,6 +1317,7 @@ exports.allFromDictAsync = allFromDictAsync;
|
|
|
1148
1317
|
exports.fromNullable = fromNullable;
|
|
1149
1318
|
exports.fromPromise = fromPromise;
|
|
1150
1319
|
exports.fromSafePromise = fromSafePromise;
|
|
1320
|
+
exports.fromSafeThrowable = fromSafeThrowable;
|
|
1151
1321
|
exports.fromThrowable = fromThrowable;
|
|
1152
1322
|
exports.isDefect = isDefect;
|
|
1153
1323
|
exports.isErr = isErr;
|