@onrails/result 0.4.0 → 0.4.2
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 +1 -1
- package/README.md +168 -12
- package/RECIPES.md +11 -9
- 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} +45 -58
- package/dist/{async-DcXR7k9K.d.cts → async.d.ts} +45 -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 -13
- package/dist/fluent.cjs.map +1 -1
- package/dist/fluent.d.cts +4 -7
- package/dist/fluent.d.ts +4 -7
- package/dist/fluent.js +15 -13
- 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 +11 -0
- package/dist/internal/ctor.d.ts +11 -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/payload.d.cts +17 -0
- package/dist/internal/payload.d.ts +17 -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 +317 -0
- package/dist/result.d.ts +317 -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 { Payload } from "./internal/payload.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,15 @@ 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, never>;
|
|
101
|
+
static ok<const T extends Payload[]>(value: T): ResultAsync<T, never>;
|
|
102
|
+
static ok<const T>(value: T): ResultAsync<T, never>;
|
|
133
103
|
static ok<T, E>(value: T): ResultAsync<T, E>;
|
|
134
104
|
/**
|
|
135
105
|
* Fantasy Land `pure` — alias of {@link ResultAsync.ok}. One lift name
|
|
136
106
|
* shared across the trio (`of` / `Maybe.of` / `ResultAsync.of`).
|
|
137
107
|
*/
|
|
138
|
-
static of<T>(value: T): ResultAsync<T, never>;
|
|
108
|
+
static of<const T extends Payload[]>(value: T): ResultAsync<T, never>;
|
|
109
|
+
static of<const T>(value: T): ResultAsync<T, never>;
|
|
139
110
|
static of<T, E>(value: T): ResultAsync<T, E>;
|
|
140
111
|
/**
|
|
141
112
|
* Lifts an error into an `Err` async result.
|
|
@@ -145,7 +116,9 @@ declare class ResultAsync<T, E> {
|
|
|
145
116
|
* const r = ResultAsync.err({ kind: "not_found" as const });
|
|
146
117
|
* ```
|
|
147
118
|
*/
|
|
148
|
-
static err<
|
|
119
|
+
static err<const E extends Payload[]>(error: E): ResultAsync<never, E>;
|
|
120
|
+
static err<const E>(error: E): ResultAsync<never, E>;
|
|
121
|
+
static err<T, E>(error: E): ResultAsync<T, E>;
|
|
149
122
|
/**
|
|
150
123
|
* Lifts an existing `Promise<Result<T, E>>` (e.g. from interop code) into a
|
|
151
124
|
* {@link ResultAsync}. A thrown defect is routed through `onDefect`,
|
|
@@ -179,7 +152,7 @@ declare class ResultAsync<T, E> {
|
|
|
179
152
|
*
|
|
180
153
|
* @example
|
|
181
154
|
* ```ts
|
|
182
|
-
* const combined = ResultAsync.combineTuple([loadCfg(), loadCatalog()]
|
|
155
|
+
* const combined = ResultAsync.combineTuple([loadCfg(), loadCatalog()]);
|
|
183
156
|
* // ResultAsync<readonly [Cfg, Catalog], CfgError | CatalogError>
|
|
184
157
|
* const r = await combined;
|
|
185
158
|
* if (isOk(r)) {
|
|
@@ -187,7 +160,7 @@ declare class ResultAsync<T, E> {
|
|
|
187
160
|
* }
|
|
188
161
|
* ```
|
|
189
162
|
*/
|
|
190
|
-
static combineTuple<const R extends readonly
|
|
163
|
+
static combineTuple<const R extends readonly unknown[]>(results: R, ..._guard: AsyncTupleGuard<R>): CombineTupleAsync<R>;
|
|
191
164
|
/**
|
|
192
165
|
* Like {@link combineTuple}, but starts every branch before awaiting (wall-clock
|
|
193
166
|
* parallel for independent IO). On failure, returns the first `Err` in input order.
|
|
@@ -198,10 +171,10 @@ declare class ResultAsync<T, E> {
|
|
|
198
171
|
* const combined = ResultAsync.combineTupleParallel([
|
|
199
172
|
* loadProfile(id),
|
|
200
173
|
* loadMetrics(id),
|
|
201
|
-
* ]
|
|
174
|
+
* ]);
|
|
202
175
|
* ```
|
|
203
176
|
*/
|
|
204
|
-
static combineTupleParallel<const R extends readonly
|
|
177
|
+
static combineTupleParallel<const R extends readonly unknown[]>(results: R, ..._guard: AsyncTupleGuard<R>): CombineTupleAsync<R>;
|
|
205
178
|
/**
|
|
206
179
|
* Transforms the `Ok` value, passing `Err` through unchanged.
|
|
207
180
|
*
|
|
@@ -221,6 +194,16 @@ declare class ResultAsync<T, E> {
|
|
|
221
194
|
* ```
|
|
222
195
|
*/
|
|
223
196
|
mapErr<F>(fn: (error: E) => F): ResultAsync<T, F>;
|
|
197
|
+
/**
|
|
198
|
+
* Transforms both tracks in one step — the async mirror of the sync
|
|
199
|
+
* `bimap`. Exactly one of `onOk` / `onErr` runs.
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* ```ts
|
|
203
|
+
* load(id).bimap(toDto, (e): AppError => ({ kind: "load", cause: e }));
|
|
204
|
+
* ```
|
|
205
|
+
*/
|
|
206
|
+
bimap<U, F>(onOk: (value: T) => U, onErr: (error: E) => F): ResultAsync<U, F>;
|
|
224
207
|
/**
|
|
225
208
|
* Canonical bind — chains a step that itself returns a `ResultAsync` or sync
|
|
226
209
|
* `Result`, short-circuiting on `Err`. Error types accumulate (`E | F`).
|
|
@@ -328,5 +311,9 @@ declare class ResultAsync<T, E> {
|
|
|
328
311
|
*/
|
|
329
312
|
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
313
|
}
|
|
331
|
-
|
|
332
|
-
|
|
314
|
+
export {};
|
|
315
|
+
/**
|
|
316
|
+
* The free-function lift helpers (`okAsync`, `errAsync`, `fromPromise`,
|
|
317
|
+
* `fromSafePromise`, `fromResult`, `fromAsync`, `asyncAfter`, `tryAsync`)
|
|
318
|
+
* live in `./async-lift.ts` and are re-exported from the package index.
|
|
319
|
+
*/
|
|
@@ -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
|