@onrails/result 0.3.1 → 0.4.1
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/DESIGN.md +4 -3
- package/README.md +166 -13
- package/RECIPES.md +6 -4
- package/dist/async-fns.cjs +52 -0
- package/dist/async-fns.cjs.map +1 -0
- package/dist/async-fns.d.cts +143 -0
- package/dist/async-fns.d.ts +143 -0
- package/dist/async-fns.js +42 -0
- package/dist/async-fns.js.map +1 -0
- package/dist/async-lift.d.cts +109 -0
- package/dist/async-lift.d.ts +109 -0
- package/dist/{async-Ci6WSL5-.d.ts → async.d.cts} +42 -58
- package/dist/{async-DcXR7k9K.d.cts → async.d.ts} +42 -58
- package/dist/collections.d.cts +105 -0
- package/dist/collections.d.ts +105 -0
- package/dist/compat/neverthrow.cjs +57 -45
- package/dist/compat/neverthrow.cjs.map +1 -1
- package/dist/compat/neverthrow.d.cts +21 -24
- package/dist/compat/neverthrow.d.ts +21 -24
- package/dist/compat/neverthrow.js +56 -44
- package/dist/compat/neverthrow.js.map +1 -1
- package/dist/extra.cjs +3 -1
- package/dist/extra.cjs.map +1 -1
- package/dist/extra.d.cts +11 -14
- package/dist/extra.d.ts +11 -14
- package/dist/extra.js +3 -1
- package/dist/extra.js.map +1 -1
- package/dist/fluent.cjs +15 -28
- package/dist/fluent.cjs.map +1 -1
- package/dist/fluent.d.cts +4 -34
- package/dist/fluent.d.ts +4 -34
- package/dist/fluent.js +16 -28
- package/dist/fluent.js.map +1 -1
- package/dist/index.cjs +77 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +28 -490
- package/dist/index.d.ts +28 -490
- package/dist/index.js +77 -53
- package/dist/index.js.map +1 -1
- package/dist/internal/ctor.d.cts +12 -0
- package/dist/internal/ctor.d.ts +12 -0
- package/dist/internal/dual.d.cts +42 -0
- package/dist/internal/dual.d.ts +42 -0
- package/dist/internal/infer.d.cts +40 -0
- package/dist/internal/infer.d.ts +40 -0
- package/dist/internal/lock.d.cts +16 -0
- package/dist/internal/lock.d.ts +16 -0
- package/dist/internal/to-error.d.cts +2 -0
- package/dist/internal/to-error.d.ts +2 -0
- package/dist/pipe.cjs +8 -0
- package/dist/pipe.cjs.map +1 -1
- package/dist/pipe.d.cts +58 -11
- package/dist/pipe.d.ts +58 -11
- package/dist/pipe.js +8 -1
- package/dist/pipe.js.map +1 -1
- package/dist/railway.cjs +87 -63
- package/dist/railway.cjs.map +1 -1
- package/dist/railway.d.cts +49 -19
- package/dist/railway.d.ts +49 -19
- package/dist/railway.js +87 -63
- package/dist/railway.js.map +1 -1
- package/dist/result.d.cts +315 -0
- package/dist/result.d.ts +315 -0
- package/dist/try-gen.cjs +3 -3
- package/dist/try-gen.cjs.map +1 -1
- package/dist/try-gen.d.cts +4 -7
- package/dist/try-gen.d.ts +4 -7
- package/dist/try-gen.js +3 -3
- package/dist/try-gen.js.map +1 -1
- package/dist/{types-BQ9vv0nD.d.cts → types.d.cts} +6 -8
- package/dist/{types-BQ9vv0nD.d.ts → types.d.ts} +6 -8
- package/package.json +69 -24
- package/skills/railway-do-notation/SKILL.md +9 -9
|
@@ -1,56 +1,25 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
* (tagged union) or a {@link ResultAsync} (class carrier), resolving to
|
|
8
|
-
* `never` for anything else. Every module that needs to extract a payload
|
|
9
|
-
* type imports from here; do not redeclare local copies.
|
|
10
|
-
*
|
|
11
|
-
* Internal only: not listed in package.json `exports` or tsup entries.
|
|
12
|
-
* The package index re-exports the pair under the same names.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Extracts the `Ok` value type from a {@link Result} or {@link ResultAsync},
|
|
17
|
-
* resolving to `never` for any other type.
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* ```ts
|
|
21
|
-
* type T = InferOk<Result<number, string>>; // number
|
|
22
|
-
* type U = InferOk<ResultAsync<User, AppError>>; // User
|
|
23
|
-
* ```
|
|
24
|
-
*/
|
|
25
|
-
type InferOk<R> = R extends {
|
|
26
|
-
_tag: "Ok";
|
|
27
|
-
readonly value: infer T;
|
|
28
|
-
} ? T : R extends ResultAsync<infer T, unknown> ? T : never;
|
|
1
|
+
import type { InferErr, InferOk } from "./internal/infer.js";
|
|
2
|
+
import type { Locked } from "./internal/lock.js";
|
|
3
|
+
import type { Result } from "./types.js";
|
|
4
|
+
import { UnexpectedError } from "./types.js";
|
|
5
|
+
type PromiseFactory<T, E> = () => Promise<Result<T, E>>;
|
|
6
|
+
type AnyResultAsync = ResultAsync<unknown, unknown>;
|
|
29
7
|
/**
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* type E = InferErr<Result<number, string>>; // string
|
|
36
|
-
* type F = InferErr<ResultAsync<User, AppError>>; // AppError
|
|
37
|
-
* ```
|
|
8
|
+
* Mirrors the sync `CombineTuple` in `./collections.ts`: the element check
|
|
9
|
+
* lives in the RETURN type, never in the parameter constraint. A
|
|
10
|
+
* `ResultAsync<unknown, unknown>` constraint contextually types the arguments
|
|
11
|
+
* and widens `okAsync(1)`'s defaulted `E = never` to `unknown`, so call sites
|
|
12
|
+
* would need hoisted intermediates to keep their error union.
|
|
38
13
|
*/
|
|
39
|
-
type
|
|
40
|
-
_tag: "Err";
|
|
41
|
-
readonly error: infer E;
|
|
42
|
-
} ? E : R extends ResultAsync<unknown, infer E> ? E : never;
|
|
43
|
-
|
|
44
|
-
type PromiseFactory<T, E> = () => Promise<Result<T, E>>;
|
|
45
|
-
type CombineTupleAsync<R extends readonly ResultAsync<unknown, unknown>[]> = ResultAsync<{
|
|
14
|
+
type CombineTupleAsync<R extends readonly unknown[]> = R[number] extends AnyResultAsync ? ResultAsync<{
|
|
46
15
|
[K in keyof R]: InferOk<R[K]>;
|
|
47
|
-
},
|
|
48
|
-
|
|
49
|
-
|
|
16
|
+
}, InferErr<R[number]>> : never;
|
|
17
|
+
/** Mirrors `TupleGuard` in `./collections.ts` — see the note there. */
|
|
18
|
+
type AsyncTupleGuard<R extends readonly unknown[]> = R[number] extends AnyResultAsync ? [] : [error: "expected an array of ResultAsync values"];
|
|
50
19
|
/**
|
|
51
20
|
* Async railway carrier. Wraps a deferred `Promise<Result<T, E>>` and exposes
|
|
52
|
-
* the same dual-track transforms as the sync {@link Result} — `map`, `
|
|
53
|
-
* `recover`, `tap`, `match`. The public API never surfaces `Promise<Result<…>>`
|
|
21
|
+
* the same dual-track transforms as the sync {@link Result} — `map`, `mapErr`,
|
|
22
|
+
* `bimap`, `flatMap`, `recover`, `tap`, `match`. The public API never surfaces `Promise<Result<…>>`
|
|
54
23
|
* directly: `await` the instance (it is thenable) or call {@link resolve} /
|
|
55
24
|
* {@link match} to settle it.
|
|
56
25
|
*
|
|
@@ -69,7 +38,7 @@ type CombineTupleAsync<R extends readonly ResultAsync<unknown, unknown>[]> = Res
|
|
|
69
38
|
* const r = await user; // Result<Profile, AppError>
|
|
70
39
|
* ```
|
|
71
40
|
*/
|
|
72
|
-
declare class ResultAsync<T, E> {
|
|
41
|
+
export declare class ResultAsync<T, E> {
|
|
73
42
|
protected readonly run: PromiseFactory<T, E>;
|
|
74
43
|
private promise;
|
|
75
44
|
protected constructor(run: PromiseFactory<T, E>);
|
|
@@ -129,13 +98,13 @@ declare class ResultAsync<T, E> {
|
|
|
129
98
|
* const r = ResultAsync.ok(42); // ResultAsync<number, never>
|
|
130
99
|
* ```
|
|
131
100
|
*/
|
|
132
|
-
static ok<T>(value: T): ResultAsync<T
|
|
101
|
+
static ok<const T>(value: T): ResultAsync<Locked<T>, never>;
|
|
133
102
|
static ok<T, E>(value: T): ResultAsync<T, E>;
|
|
134
103
|
/**
|
|
135
104
|
* Fantasy Land `pure` — alias of {@link ResultAsync.ok}. One lift name
|
|
136
105
|
* shared across the trio (`of` / `Maybe.of` / `ResultAsync.of`).
|
|
137
106
|
*/
|
|
138
|
-
static of<T>(value: T): ResultAsync<T
|
|
107
|
+
static of<const T>(value: T): ResultAsync<Locked<T>, never>;
|
|
139
108
|
static of<T, E>(value: T): ResultAsync<T, E>;
|
|
140
109
|
/**
|
|
141
110
|
* Lifts an error into an `Err` async result.
|
|
@@ -145,7 +114,8 @@ declare class ResultAsync<T, E> {
|
|
|
145
114
|
* const r = ResultAsync.err({ kind: "not_found" as const });
|
|
146
115
|
* ```
|
|
147
116
|
*/
|
|
148
|
-
static err<
|
|
117
|
+
static err<const E>(error: E): ResultAsync<never, Locked<E>>;
|
|
118
|
+
static err<T, E>(error: E): ResultAsync<T, E>;
|
|
149
119
|
/**
|
|
150
120
|
* Lifts an existing `Promise<Result<T, E>>` (e.g. from interop code) into a
|
|
151
121
|
* {@link ResultAsync}. A thrown defect is routed through `onDefect`,
|
|
@@ -179,7 +149,7 @@ declare class ResultAsync<T, E> {
|
|
|
179
149
|
*
|
|
180
150
|
* @example
|
|
181
151
|
* ```ts
|
|
182
|
-
* const combined = ResultAsync.combineTuple([loadCfg(), loadCatalog()]
|
|
152
|
+
* const combined = ResultAsync.combineTuple([loadCfg(), loadCatalog()]);
|
|
183
153
|
* // ResultAsync<readonly [Cfg, Catalog], CfgError | CatalogError>
|
|
184
154
|
* const r = await combined;
|
|
185
155
|
* if (isOk(r)) {
|
|
@@ -187,7 +157,7 @@ declare class ResultAsync<T, E> {
|
|
|
187
157
|
* }
|
|
188
158
|
* ```
|
|
189
159
|
*/
|
|
190
|
-
static combineTuple<const R extends readonly
|
|
160
|
+
static combineTuple<const R extends readonly unknown[]>(results: R, ..._guard: AsyncTupleGuard<R>): CombineTupleAsync<R>;
|
|
191
161
|
/**
|
|
192
162
|
* Like {@link combineTuple}, but starts every branch before awaiting (wall-clock
|
|
193
163
|
* parallel for independent IO). On failure, returns the first `Err` in input order.
|
|
@@ -198,10 +168,10 @@ declare class ResultAsync<T, E> {
|
|
|
198
168
|
* const combined = ResultAsync.combineTupleParallel([
|
|
199
169
|
* loadProfile(id),
|
|
200
170
|
* loadMetrics(id),
|
|
201
|
-
* ]
|
|
171
|
+
* ]);
|
|
202
172
|
* ```
|
|
203
173
|
*/
|
|
204
|
-
static combineTupleParallel<const R extends readonly
|
|
174
|
+
static combineTupleParallel<const R extends readonly unknown[]>(results: R, ..._guard: AsyncTupleGuard<R>): CombineTupleAsync<R>;
|
|
205
175
|
/**
|
|
206
176
|
* Transforms the `Ok` value, passing `Err` through unchanged.
|
|
207
177
|
*
|
|
@@ -221,6 +191,16 @@ declare class ResultAsync<T, E> {
|
|
|
221
191
|
* ```
|
|
222
192
|
*/
|
|
223
193
|
mapErr<F>(fn: (error: E) => F): ResultAsync<T, F>;
|
|
194
|
+
/**
|
|
195
|
+
* Transforms both tracks in one step — the async mirror of the sync
|
|
196
|
+
* `bimap`. Exactly one of `onOk` / `onErr` runs.
|
|
197
|
+
*
|
|
198
|
+
* @example
|
|
199
|
+
* ```ts
|
|
200
|
+
* load(id).bimap(toDto, (e): AppError => ({ kind: "load", cause: e }));
|
|
201
|
+
* ```
|
|
202
|
+
*/
|
|
203
|
+
bimap<U, F>(onOk: (value: T) => U, onErr: (error: E) => F): ResultAsync<U, F>;
|
|
224
204
|
/**
|
|
225
205
|
* Canonical bind — chains a step that itself returns a `ResultAsync` or sync
|
|
226
206
|
* `Result`, short-circuiting on `Err`. Error types accumulate (`E | F`).
|
|
@@ -328,5 +308,9 @@ declare class ResultAsync<T, E> {
|
|
|
328
308
|
*/
|
|
329
309
|
then<R1 = Result<T, E>, R2 = never>(onfulfilled?: ((value: Result<T, E>) => R1 | PromiseLike<R1>) | undefined | null, onrejected?: ((reason: unknown) => R2 | PromiseLike<R2>) | undefined | null): Promise<R1 | R2>;
|
|
330
310
|
}
|
|
331
|
-
|
|
332
|
-
|
|
311
|
+
export {};
|
|
312
|
+
/**
|
|
313
|
+
* The free-function lift helpers (`okAsync`, `errAsync`, `fromPromise`,
|
|
314
|
+
* `fromSafePromise`, `fromResult`, `fromAsync`, `asyncAfter`, `tryAsync`)
|
|
315
|
+
* live in `./async-lift.ts` and are re-exported from the package index.
|
|
316
|
+
*/
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @onrails/result — sync aggregation, one module, two axes:
|
|
3
|
+
*
|
|
4
|
+
* short-circuit (first `Err` wins) — {@link combine} / {@link combineTuple}
|
|
5
|
+
* accumulate expected failures — {@link validateAll} / {@link validateTuple}
|
|
6
|
+
*
|
|
7
|
+
* The accumulate pair collects every failure into a readonly array by
|
|
8
|
+
* default, or folds them with an explicit `combineErrors` when given one.
|
|
9
|
+
*/
|
|
10
|
+
import type { InferErr, InferOk } from "./internal/infer.js";
|
|
11
|
+
import type { Result } from "./types.js";
|
|
12
|
+
/**
|
|
13
|
+
* Combines a homogeneous array of results into a single result holding an
|
|
14
|
+
* array of the `Ok` values, in input order. Short-circuits on the first `Err`
|
|
15
|
+
* (first failure wins). For heterogeneous tuples that preserve per-index
|
|
16
|
+
* types, use {@link combineTuple}.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* combine([ok(1), ok(2)]); // Ok([1, 2])
|
|
21
|
+
* combine([ok(1), err("e")]); // Err("e")
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare const combine: <T, E>(results: readonly Result<T, E>[]) => Result<T[], E>;
|
|
25
|
+
type AnyResult = Result<unknown, unknown>;
|
|
26
|
+
/** Positionally preserved `Ok` payloads for a tuple of results. */
|
|
27
|
+
type OkTuple<R extends readonly unknown[]> = {
|
|
28
|
+
[K in keyof R]: InferOk<R[K]>;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* The element check lives in the RETURN type, never in the parameter
|
|
32
|
+
* constraint. A `readonly Result<unknown, unknown>[]` constraint contextually
|
|
33
|
+
* types the arguments, which widens `ok(1)`'s defaulted `E = never` — and
|
|
34
|
+
* `err(e)`'s `T = never` — all the way to `unknown`. Holding the parameter at
|
|
35
|
+
* a bare `R` keeps both channels precise for inline literals, so call sites
|
|
36
|
+
* need neither `as const` nor hoisted intermediates.
|
|
37
|
+
*/
|
|
38
|
+
type CombineTuple<R extends readonly unknown[]> = R[number] extends AnyResult ? Result<OkTuple<R>, InferErr<R[number]>> : never;
|
|
39
|
+
/**
|
|
40
|
+
* Restores the "every element is a Result" check the parameter constraint used
|
|
41
|
+
* to provide. Resolves to `[]` for a well-formed tuple and to a one-element
|
|
42
|
+
* tuple otherwise, so a bad call fails at the call site (with the message
|
|
43
|
+
* visible in signature help) instead of silently yielding `never`.
|
|
44
|
+
*/
|
|
45
|
+
type TupleGuard<R extends readonly unknown[]> = R[number] extends AnyResult ? [] : [error: "expected an array of Result values"];
|
|
46
|
+
/**
|
|
47
|
+
* Heterogeneous tuple combine — like {@link combine} but preserves each
|
|
48
|
+
* branch's `Ok` type by position, so the result destructures type-safely.
|
|
49
|
+
* Short-circuits on the first `Err` in input order (neverthrow-style).
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```ts
|
|
53
|
+
* const r = combineTuple([ok(1), ok("x")]);
|
|
54
|
+
* // Result<readonly [number, string], never> — no `as const` needed
|
|
55
|
+
* if (isOk(r)) {
|
|
56
|
+
* const [n, s] = r.value; // typed per position
|
|
57
|
+
* }
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export declare const combineTuple: <const R extends readonly unknown[]>(results: R, ..._guard: TupleGuard<R>) => CombineTuple<R>;
|
|
61
|
+
/**
|
|
62
|
+
* Accumulate independent validation failures. Returns `Ok<T[]>` only when
|
|
63
|
+
* every input is `Ok`. Without a combiner, failures are collected into a
|
|
64
|
+
* readonly array; with `combineErrors` they are folded into a single `E`.
|
|
65
|
+
*
|
|
66
|
+
* Unlike {@link combine}, this does **not** short-circuit on first failure —
|
|
67
|
+
* use for independent checks where you want to report all problems at once.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```ts
|
|
71
|
+
* const checks: Result<string, string[]>[] = [ok("Ada"), err(["age required"])];
|
|
72
|
+
*
|
|
73
|
+
* validateAll(checks);
|
|
74
|
+
* // Result<string[], readonly string[][]>
|
|
75
|
+
*
|
|
76
|
+
* validateAll(checks, (left, right) => [...left, ...right]);
|
|
77
|
+
* // Result<string[], string[]>
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export declare function validateAll<T, E>(results: readonly Result<T, E>[]): Result<T[], readonly E[]>;
|
|
81
|
+
export declare function validateAll<T, E>(results: readonly Result<T, E>[], combineErrors: (left: E, right: E) => E): Result<T[], E>;
|
|
82
|
+
/**
|
|
83
|
+
* Tuple-preserving variant of {@link validateAll}. Heterogeneous input tuple
|
|
84
|
+
* → preserved `Ok` tuple shape. Without a combiner, the error union is
|
|
85
|
+
* collected into a readonly array; with `combineErrors`, all inputs must
|
|
86
|
+
* share the error type `E` and failures fold into a single `E`.
|
|
87
|
+
*
|
|
88
|
+
* Like {@link combineTuple}, the element check lives in the return type, so
|
|
89
|
+
* inline literals keep their precise error types without `as const`.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```ts
|
|
93
|
+
* const name: Result<string, string[]> = ok("Ada");
|
|
94
|
+
* const age: Result<number, string[]> = ok(36);
|
|
95
|
+
*
|
|
96
|
+
* validateTuple([name, age]);
|
|
97
|
+
* // Result<readonly [string, number], readonly string[][]>
|
|
98
|
+
*
|
|
99
|
+
* validateTuple([name, age], (l, r) => [...l, ...r]);
|
|
100
|
+
* // Result<readonly [string, number], string[]>
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
export declare function validateTuple<const R extends readonly unknown[]>(results: R, ..._guard: TupleGuard<R>): R[number] extends AnyResult ? Result<OkTuple<R>, readonly InferErr<R[number]>[]> : never;
|
|
104
|
+
export declare function validateTuple<const R extends readonly unknown[], E = InferErr<R[number]>>(results: R, combineErrors: (left: E, right: E) => E, ..._guard: TupleGuard<R>): R[number] extends AnyResult ? Result<OkTuple<R>, E> : never;
|
|
105
|
+
export {};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @onrails/result — sync aggregation, one module, two axes:
|
|
3
|
+
*
|
|
4
|
+
* short-circuit (first `Err` wins) — {@link combine} / {@link combineTuple}
|
|
5
|
+
* accumulate expected failures — {@link validateAll} / {@link validateTuple}
|
|
6
|
+
*
|
|
7
|
+
* The accumulate pair collects every failure into a readonly array by
|
|
8
|
+
* default, or folds them with an explicit `combineErrors` when given one.
|
|
9
|
+
*/
|
|
10
|
+
import type { InferErr, InferOk } from "./internal/infer.js";
|
|
11
|
+
import type { Result } from "./types.js";
|
|
12
|
+
/**
|
|
13
|
+
* Combines a homogeneous array of results into a single result holding an
|
|
14
|
+
* array of the `Ok` values, in input order. Short-circuits on the first `Err`
|
|
15
|
+
* (first failure wins). For heterogeneous tuples that preserve per-index
|
|
16
|
+
* types, use {@link combineTuple}.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* combine([ok(1), ok(2)]); // Ok([1, 2])
|
|
21
|
+
* combine([ok(1), err("e")]); // Err("e")
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare const combine: <T, E>(results: readonly Result<T, E>[]) => Result<T[], E>;
|
|
25
|
+
type AnyResult = Result<unknown, unknown>;
|
|
26
|
+
/** Positionally preserved `Ok` payloads for a tuple of results. */
|
|
27
|
+
type OkTuple<R extends readonly unknown[]> = {
|
|
28
|
+
[K in keyof R]: InferOk<R[K]>;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* The element check lives in the RETURN type, never in the parameter
|
|
32
|
+
* constraint. A `readonly Result<unknown, unknown>[]` constraint contextually
|
|
33
|
+
* types the arguments, which widens `ok(1)`'s defaulted `E = never` — and
|
|
34
|
+
* `err(e)`'s `T = never` — all the way to `unknown`. Holding the parameter at
|
|
35
|
+
* a bare `R` keeps both channels precise for inline literals, so call sites
|
|
36
|
+
* need neither `as const` nor hoisted intermediates.
|
|
37
|
+
*/
|
|
38
|
+
type CombineTuple<R extends readonly unknown[]> = R[number] extends AnyResult ? Result<OkTuple<R>, InferErr<R[number]>> : never;
|
|
39
|
+
/**
|
|
40
|
+
* Restores the "every element is a Result" check the parameter constraint used
|
|
41
|
+
* to provide. Resolves to `[]` for a well-formed tuple and to a one-element
|
|
42
|
+
* tuple otherwise, so a bad call fails at the call site (with the message
|
|
43
|
+
* visible in signature help) instead of silently yielding `never`.
|
|
44
|
+
*/
|
|
45
|
+
type TupleGuard<R extends readonly unknown[]> = R[number] extends AnyResult ? [] : [error: "expected an array of Result values"];
|
|
46
|
+
/**
|
|
47
|
+
* Heterogeneous tuple combine — like {@link combine} but preserves each
|
|
48
|
+
* branch's `Ok` type by position, so the result destructures type-safely.
|
|
49
|
+
* Short-circuits on the first `Err` in input order (neverthrow-style).
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```ts
|
|
53
|
+
* const r = combineTuple([ok(1), ok("x")]);
|
|
54
|
+
* // Result<readonly [number, string], never> — no `as const` needed
|
|
55
|
+
* if (isOk(r)) {
|
|
56
|
+
* const [n, s] = r.value; // typed per position
|
|
57
|
+
* }
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export declare const combineTuple: <const R extends readonly unknown[]>(results: R, ..._guard: TupleGuard<R>) => CombineTuple<R>;
|
|
61
|
+
/**
|
|
62
|
+
* Accumulate independent validation failures. Returns `Ok<T[]>` only when
|
|
63
|
+
* every input is `Ok`. Without a combiner, failures are collected into a
|
|
64
|
+
* readonly array; with `combineErrors` they are folded into a single `E`.
|
|
65
|
+
*
|
|
66
|
+
* Unlike {@link combine}, this does **not** short-circuit on first failure —
|
|
67
|
+
* use for independent checks where you want to report all problems at once.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```ts
|
|
71
|
+
* const checks: Result<string, string[]>[] = [ok("Ada"), err(["age required"])];
|
|
72
|
+
*
|
|
73
|
+
* validateAll(checks);
|
|
74
|
+
* // Result<string[], readonly string[][]>
|
|
75
|
+
*
|
|
76
|
+
* validateAll(checks, (left, right) => [...left, ...right]);
|
|
77
|
+
* // Result<string[], string[]>
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export declare function validateAll<T, E>(results: readonly Result<T, E>[]): Result<T[], readonly E[]>;
|
|
81
|
+
export declare function validateAll<T, E>(results: readonly Result<T, E>[], combineErrors: (left: E, right: E) => E): Result<T[], E>;
|
|
82
|
+
/**
|
|
83
|
+
* Tuple-preserving variant of {@link validateAll}. Heterogeneous input tuple
|
|
84
|
+
* → preserved `Ok` tuple shape. Without a combiner, the error union is
|
|
85
|
+
* collected into a readonly array; with `combineErrors`, all inputs must
|
|
86
|
+
* share the error type `E` and failures fold into a single `E`.
|
|
87
|
+
*
|
|
88
|
+
* Like {@link combineTuple}, the element check lives in the return type, so
|
|
89
|
+
* inline literals keep their precise error types without `as const`.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```ts
|
|
93
|
+
* const name: Result<string, string[]> = ok("Ada");
|
|
94
|
+
* const age: Result<number, string[]> = ok(36);
|
|
95
|
+
*
|
|
96
|
+
* validateTuple([name, age]);
|
|
97
|
+
* // Result<readonly [string, number], readonly string[][]>
|
|
98
|
+
*
|
|
99
|
+
* validateTuple([name, age], (l, r) => [...l, ...r]);
|
|
100
|
+
* // Result<readonly [string, number], string[]>
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
export declare function validateTuple<const R extends readonly unknown[]>(results: R, ..._guard: TupleGuard<R>): R[number] extends AnyResult ? Result<OkTuple<R>, readonly InferErr<R[number]>[]> : never;
|
|
104
|
+
export declare function validateTuple<const R extends readonly unknown[], E = InferErr<R[number]>>(results: R, combineErrors: (left: E, right: E) => E, ..._guard: TupleGuard<R>): R[number] extends AnyResult ? Result<OkTuple<R>, E> : never;
|
|
105
|
+
export {};
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
// src/internal/ctor.ts
|
|
4
|
+
var mkOk = (value) => ({
|
|
5
|
+
_tag: "Ok",
|
|
6
|
+
value
|
|
7
|
+
});
|
|
8
|
+
var mkErr = (error) => ({
|
|
9
|
+
_tag: "Err",
|
|
10
|
+
error
|
|
11
|
+
});
|
|
12
|
+
|
|
3
13
|
// src/internal/dual.ts
|
|
4
14
|
var dual = (arity, body) => {
|
|
5
15
|
const run = body;
|
|
@@ -8,38 +18,34 @@ var dual = (arity, body) => {
|
|
|
8
18
|
};
|
|
9
19
|
|
|
10
20
|
// src/result.ts
|
|
11
|
-
var ok = (value) => ({
|
|
12
|
-
_tag: "Ok",
|
|
13
|
-
value
|
|
14
|
-
});
|
|
15
|
-
var err = (error) => ({
|
|
16
|
-
_tag: "Err",
|
|
17
|
-
error
|
|
18
|
-
});
|
|
19
21
|
var isOk = (result) => result._tag === "Ok";
|
|
20
22
|
var isErr = (result) => result._tag === "Err";
|
|
21
23
|
var map = dual(
|
|
22
24
|
2,
|
|
23
|
-
(result, fn) => isOk(result) ?
|
|
25
|
+
(result, fn) => isOk(result) ? mkOk(fn(result.value)) : mkErr(result.error)
|
|
24
26
|
);
|
|
25
27
|
var mapErr = dual(
|
|
26
28
|
2,
|
|
27
|
-
(result, fn) => isErr(result) ?
|
|
29
|
+
(result, fn) => isErr(result) ? mkErr(fn(result.error)) : mkOk(result.value)
|
|
30
|
+
);
|
|
31
|
+
var bimap = dual(
|
|
32
|
+
3,
|
|
33
|
+
(result, onOk, onErr) => isOk(result) ? mkOk(onOk(result.value)) : mkErr(onErr(result.error))
|
|
28
34
|
);
|
|
29
35
|
var flatMap = dual(
|
|
30
36
|
2,
|
|
31
|
-
(result, fn) => isOk(result) ? fn(result.value) :
|
|
37
|
+
(result, fn) => isOk(result) ? fn(result.value) : mkErr(result.error)
|
|
32
38
|
);
|
|
33
39
|
var unwrapOr = dual(
|
|
34
40
|
2,
|
|
35
41
|
(result, defaultValue) => isOk(result) ? result.value : defaultValue
|
|
36
42
|
);
|
|
37
|
-
function
|
|
43
|
+
function fromThrowable(fn, onThrow) {
|
|
38
44
|
return (...args) => {
|
|
39
45
|
try {
|
|
40
|
-
return
|
|
46
|
+
return mkOk(fn(...args));
|
|
41
47
|
} catch (error) {
|
|
42
|
-
return
|
|
48
|
+
return mkErr(onThrow(error));
|
|
43
49
|
}
|
|
44
50
|
};
|
|
45
51
|
}
|
|
@@ -59,11 +65,11 @@ var sequenceSettled = (settled) => {
|
|
|
59
65
|
const values = [];
|
|
60
66
|
for (const result of settled) {
|
|
61
67
|
if (isErr(result)) {
|
|
62
|
-
return
|
|
68
|
+
return mkErr(result.error);
|
|
63
69
|
}
|
|
64
70
|
values.push(result.value);
|
|
65
71
|
}
|
|
66
|
-
return
|
|
72
|
+
return mkOk(values);
|
|
67
73
|
};
|
|
68
74
|
var ResultAsync = class _ResultAsync {
|
|
69
75
|
constructor(run) {
|
|
@@ -100,9 +106,9 @@ var ResultAsync = class _ResultAsync {
|
|
|
100
106
|
static fromPromise(promise, onReject) {
|
|
101
107
|
return new _ResultAsync(async () => {
|
|
102
108
|
try {
|
|
103
|
-
return
|
|
109
|
+
return mkOk(await promise);
|
|
104
110
|
} catch (error) {
|
|
105
|
-
return
|
|
111
|
+
return mkErr(onReject(error));
|
|
106
112
|
}
|
|
107
113
|
});
|
|
108
114
|
}
|
|
@@ -116,7 +122,7 @@ var ResultAsync = class _ResultAsync {
|
|
|
116
122
|
* ```
|
|
117
123
|
*/
|
|
118
124
|
static fromSafePromise(promise) {
|
|
119
|
-
return new _ResultAsync(async () =>
|
|
125
|
+
return new _ResultAsync(async () => mkOk(await promise));
|
|
120
126
|
}
|
|
121
127
|
/**
|
|
122
128
|
* Defers work until {@link resolve}. Unlike {@link fromPromise}, the factory
|
|
@@ -134,21 +140,13 @@ var ResultAsync = class _ResultAsync {
|
|
|
134
140
|
return new _ResultAsync(fn);
|
|
135
141
|
}
|
|
136
142
|
static ok(value) {
|
|
137
|
-
return new _ResultAsync(async () =>
|
|
143
|
+
return new _ResultAsync(async () => mkOk(value));
|
|
138
144
|
}
|
|
139
145
|
static of(value) {
|
|
140
146
|
return _ResultAsync.ok(value);
|
|
141
147
|
}
|
|
142
|
-
/**
|
|
143
|
-
* Lifts an error into an `Err` async result.
|
|
144
|
-
*
|
|
145
|
-
* @example
|
|
146
|
-
* ```ts
|
|
147
|
-
* const r = ResultAsync.err({ kind: "not_found" as const });
|
|
148
|
-
* ```
|
|
149
|
-
*/
|
|
150
148
|
static err(error) {
|
|
151
|
-
return new _ResultAsync(async () =>
|
|
149
|
+
return new _ResultAsync(async () => mkErr(error));
|
|
152
150
|
}
|
|
153
151
|
/**
|
|
154
152
|
* Lifts an existing `Promise<Result<T, E>>` (e.g. from interop code) into a
|
|
@@ -166,7 +164,7 @@ var ResultAsync = class _ResultAsync {
|
|
|
166
164
|
try {
|
|
167
165
|
return await promise;
|
|
168
166
|
} catch (error) {
|
|
169
|
-
return
|
|
167
|
+
return mkErr(mapDefect(error));
|
|
170
168
|
}
|
|
171
169
|
});
|
|
172
170
|
}
|
|
@@ -188,11 +186,11 @@ var ResultAsync = class _ResultAsync {
|
|
|
188
186
|
for (const ra of results) {
|
|
189
187
|
const result = await ra.resolve();
|
|
190
188
|
if (isErr(result)) {
|
|
191
|
-
return
|
|
189
|
+
return mkErr(result.error);
|
|
192
190
|
}
|
|
193
191
|
values.push(result.value);
|
|
194
192
|
}
|
|
195
|
-
return
|
|
193
|
+
return mkOk(values);
|
|
196
194
|
});
|
|
197
195
|
}
|
|
198
196
|
/**
|
|
@@ -204,7 +202,7 @@ var ResultAsync = class _ResultAsync {
|
|
|
204
202
|
*
|
|
205
203
|
* @example
|
|
206
204
|
* ```ts
|
|
207
|
-
* const combined = ResultAsync.combineTuple([loadCfg(), loadCatalog()]
|
|
205
|
+
* const combined = ResultAsync.combineTuple([loadCfg(), loadCatalog()]);
|
|
208
206
|
* // ResultAsync<readonly [Cfg, Catalog], CfgError | CatalogError>
|
|
209
207
|
* const r = await combined;
|
|
210
208
|
* if (isOk(r)) {
|
|
@@ -212,7 +210,7 @@ var ResultAsync = class _ResultAsync {
|
|
|
212
210
|
* }
|
|
213
211
|
* ```
|
|
214
212
|
*/
|
|
215
|
-
static combineTuple(results) {
|
|
213
|
+
static combineTuple(results, ..._guard) {
|
|
216
214
|
return _ResultAsync.combine(
|
|
217
215
|
results
|
|
218
216
|
);
|
|
@@ -227,12 +225,14 @@ var ResultAsync = class _ResultAsync {
|
|
|
227
225
|
* const combined = ResultAsync.combineTupleParallel([
|
|
228
226
|
* loadProfile(id),
|
|
229
227
|
* loadMetrics(id),
|
|
230
|
-
* ]
|
|
228
|
+
* ]);
|
|
231
229
|
* ```
|
|
232
230
|
*/
|
|
233
|
-
static combineTupleParallel(results) {
|
|
231
|
+
static combineTupleParallel(results, ..._guard) {
|
|
234
232
|
return new _ResultAsync(
|
|
235
|
-
async () => sequenceSettled(
|
|
233
|
+
async () => sequenceSettled(
|
|
234
|
+
await Promise.all(results.map((ra) => ra.resolve()))
|
|
235
|
+
)
|
|
236
236
|
);
|
|
237
237
|
}
|
|
238
238
|
/**
|
|
@@ -258,6 +258,18 @@ var ResultAsync = class _ResultAsync {
|
|
|
258
258
|
mapErr(fn) {
|
|
259
259
|
return new _ResultAsync(async () => mapErr(await this.resolve(), fn));
|
|
260
260
|
}
|
|
261
|
+
/**
|
|
262
|
+
* Transforms both tracks in one step — the async mirror of the sync
|
|
263
|
+
* `bimap`. Exactly one of `onOk` / `onErr` runs.
|
|
264
|
+
*
|
|
265
|
+
* @example
|
|
266
|
+
* ```ts
|
|
267
|
+
* load(id).bimap(toDto, (e): AppError => ({ kind: "load", cause: e }));
|
|
268
|
+
* ```
|
|
269
|
+
*/
|
|
270
|
+
bimap(onOk, onErr) {
|
|
271
|
+
return new _ResultAsync(async () => bimap(await this.resolve(), onOk, onErr));
|
|
272
|
+
}
|
|
261
273
|
/**
|
|
262
274
|
* Canonical bind — chains a step that itself returns a `ResultAsync` or sync
|
|
263
275
|
* `Result`, short-circuiting on `Err`. Error types accumulate (`E | F`).
|
|
@@ -426,12 +438,12 @@ var ResultAsync = class _ResultAsync {
|
|
|
426
438
|
var combine = (results) => {
|
|
427
439
|
const values = [];
|
|
428
440
|
for (const result of results) {
|
|
429
|
-
if (isErr(result)) return
|
|
441
|
+
if (isErr(result)) return mkErr(result.error);
|
|
430
442
|
values.push(result.value);
|
|
431
443
|
}
|
|
432
|
-
return
|
|
444
|
+
return mkOk(values);
|
|
433
445
|
};
|
|
434
|
-
var combineTuple = (results) => (
|
|
446
|
+
var combineTuple = (results, ..._guard) => (
|
|
435
447
|
// Runtime identical to combine; the cast restores per-index tuple types.
|
|
436
448
|
combine(results)
|
|
437
449
|
);
|
|
@@ -443,7 +455,7 @@ var CompatResult = class _CompatResult {
|
|
|
443
455
|
}
|
|
444
456
|
inner;
|
|
445
457
|
static fromThrowable(fn, onThrow) {
|
|
446
|
-
const wrapped =
|
|
458
|
+
const wrapped = fromThrowable(fn, onThrow);
|
|
447
459
|
return (...args) => new _CompatResult(wrapped(...args));
|
|
448
460
|
}
|
|
449
461
|
static combine(results) {
|
|
@@ -498,8 +510,8 @@ var CompatResult = class _CompatResult {
|
|
|
498
510
|
}
|
|
499
511
|
};
|
|
500
512
|
var Result = CompatResult;
|
|
501
|
-
var
|
|
502
|
-
var
|
|
513
|
+
var ok = (value) => new CompatResult(mkOk(value));
|
|
514
|
+
var err = (error) => new CompatResult(mkErr(error));
|
|
503
515
|
var CompatResultAsync = class _CompatResultAsync {
|
|
504
516
|
constructor(inner) {
|
|
505
517
|
this.inner = inner;
|
|
@@ -626,11 +638,11 @@ exports.CompatResult = CompatResult;
|
|
|
626
638
|
exports.CompatResultAsync = CompatResultAsync;
|
|
627
639
|
exports.Result = Result;
|
|
628
640
|
exports.ResultAsync = CompatResultAsync;
|
|
629
|
-
exports.err =
|
|
641
|
+
exports.err = err;
|
|
630
642
|
exports.errAsync = errAsync;
|
|
631
643
|
exports.fromPromise = fromPromise;
|
|
632
644
|
exports.fromSafePromise = fromSafePromise;
|
|
633
|
-
exports.ok =
|
|
645
|
+
exports.ok = ok;
|
|
634
646
|
exports.okAsync = okAsync;
|
|
635
647
|
//# sourceMappingURL=neverthrow.cjs.map
|
|
636
648
|
//# sourceMappingURL=neverthrow.cjs.map
|