rsult 1.4.0 → 2.0.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/package.json +7 -6
- package/readme.md +161 -5
- package/rust/option.rs +2822 -0
- package/rust/result.rs +2207 -0
- package/src/lib.ts +3 -1
- package/src/option-async.test.ts +410 -0
- package/src/option-async.ts +467 -0
- package/src/option.test.ts +101 -0
- package/src/option.ts +480 -266
- package/src/result-async.test.ts +485 -0
- package/src/result-async.ts +635 -0
- package/src/result.test.ts +36 -0
- package/src/result.ts +418 -340
- package/src/types.test.ts +409 -0
- package/dist/lib.d.ts +0 -2
- package/dist/lib.js +0 -19
- package/dist/lib.js.map +0 -1
- package/dist/option.d.ts +0 -307
- package/dist/option.js +0 -195
- package/dist/option.js.map +0 -1
- package/dist/result.d.ts +0 -410
- package/dist/result.js +0 -231
- package/dist/result.js.map +0 -1
package/src/result.ts
CHANGED
|
@@ -1,395 +1,305 @@
|
|
|
1
1
|
import { Option, None, Some } from './option';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
// ============================================================================
|
|
4
|
+
// Type-Level Utilities
|
|
5
|
+
// ============================================================================
|
|
6
|
+
|
|
7
|
+
/** Unique brand symbols for nominal typing */
|
|
8
|
+
declare const OkBrand: unique symbol;
|
|
9
|
+
declare const ErrBrand: unique symbol;
|
|
10
|
+
|
|
11
|
+
/** Extract the Ok type from a Result */
|
|
12
|
+
export type UnwrapOk<R> = R extends Result<infer T, any> ? T : never;
|
|
13
|
+
|
|
14
|
+
/** Extract the Err type from a Result */
|
|
15
|
+
export type UnwrapErr<R> = R extends Result<any, infer E> ? E : never;
|
|
16
|
+
|
|
17
|
+
/** Unwrap nested Result types for flatten() */
|
|
18
|
+
export type FlattenResult<T, E> = T extends Result<infer U, infer E2>
|
|
19
|
+
? Result<U, E | E2>
|
|
20
|
+
: Result<T, E>;
|
|
21
|
+
|
|
22
|
+
/** Type-level check for nested Results */
|
|
23
|
+
export type IsNestedResult<T> = T extends Result<any, any> ? true : false;
|
|
24
|
+
|
|
25
|
+
// ============================================================================
|
|
26
|
+
// Result Type Definition
|
|
27
|
+
// ============================================================================
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* A discriminated union representing either success (Ok) or failure (Err).
|
|
31
|
+
*
|
|
32
|
+
* @typeParam T - The success value type
|
|
33
|
+
* @typeParam E - The error value type
|
|
34
|
+
*/
|
|
35
|
+
export type Result<T, E> = ResultOk<T, E> | ResultErr<T, E>;
|
|
36
|
+
|
|
37
|
+
// ============================================================================
|
|
38
|
+
// Core Interfaces
|
|
39
|
+
// ============================================================================
|
|
5
40
|
|
|
6
41
|
export interface IResultCore<T, E> {
|
|
7
42
|
/**
|
|
8
|
-
*
|
|
9
|
-
* @returns true if the result is `ResultOk`, otherwise false.
|
|
43
|
+
* Returns `true` if the result is `Ok`.
|
|
10
44
|
*
|
|
11
|
-
*
|
|
12
|
-
* const result = Ok(5);
|
|
13
|
-
* if (result.is_ok()) {
|
|
14
|
-
* console.log("Result is Ok");
|
|
15
|
-
* }
|
|
45
|
+
* This is a type guard that narrows the type to `ResultOk<T, E>`.
|
|
16
46
|
*/
|
|
17
47
|
is_ok(): this is ResultOk<T, E>;
|
|
18
48
|
|
|
19
49
|
/**
|
|
20
|
-
*
|
|
21
|
-
* @returns true if the result is `ResultErr`, otherwise false.
|
|
50
|
+
* Returns `true` if the result is `Err`.
|
|
22
51
|
*
|
|
23
|
-
*
|
|
24
|
-
* const result = Err(new Error("Error"));
|
|
25
|
-
* if (result.is_err()) {
|
|
26
|
-
* console.log("Result is Err");
|
|
27
|
-
* }
|
|
52
|
+
* This is a type guard that narrows the type to `ResultErr<T, E>`.
|
|
28
53
|
*/
|
|
29
54
|
is_err(): this is ResultErr<T, E>;
|
|
30
55
|
|
|
31
56
|
/**
|
|
32
|
-
*
|
|
33
|
-
* @returns `Some` containing the value if the result is `ResultOk`, otherwise `None`.
|
|
57
|
+
* Converts from `Result<T, E>` to `Option<T>`.
|
|
34
58
|
*
|
|
35
|
-
*
|
|
36
|
-
* const result = Ok(5);
|
|
37
|
-
* const value = result.ok();
|
|
38
|
-
* if (value.is_some()) {
|
|
39
|
-
* console.log("Value:", value.unwrap());
|
|
40
|
-
* }
|
|
59
|
+
* Returns `Some(value)` if `Ok`, otherwise `None`.
|
|
41
60
|
*/
|
|
42
61
|
ok(): Option<T>;
|
|
43
62
|
|
|
44
63
|
/**
|
|
45
|
-
*
|
|
46
|
-
* @returns `Some` containing the error if the result is `ResultErr`, otherwise `None`.
|
|
64
|
+
* Converts from `Result<T, E>` to `Option<E>`.
|
|
47
65
|
*
|
|
48
|
-
*
|
|
49
|
-
* const result = Err(new Error("Error"));
|
|
50
|
-
* const error = result.err();
|
|
51
|
-
* if (error.is_some()) {
|
|
52
|
-
* console.log("Error:", error.unwrap());
|
|
53
|
-
* }
|
|
66
|
+
* Returns `Some(error)` if `Err`, otherwise `None`.
|
|
54
67
|
*/
|
|
55
68
|
err(): Option<E>;
|
|
56
69
|
|
|
57
70
|
/**
|
|
58
|
-
* Returns the contained `
|
|
59
|
-
* the result is a `ResultErr`.
|
|
60
|
-
* @param msg The message to throw with if the result is an error.
|
|
61
|
-
* @returns The contained `ResultOk` value.
|
|
71
|
+
* Returns the contained `Ok` value, or throws with the provided message.
|
|
62
72
|
*
|
|
63
|
-
*
|
|
64
|
-
* const result = Ok(5);
|
|
65
|
-
* console.log(result.expect("This should not fail"));
|
|
73
|
+
* @throws Error with `msg` if this is `Err`
|
|
66
74
|
*/
|
|
67
75
|
expect(msg: string): T;
|
|
68
76
|
|
|
69
77
|
/**
|
|
70
|
-
*
|
|
71
|
-
* @returns The `ResultOk` value.
|
|
72
|
-
* @throws Throws if the result is `ResultErr`.
|
|
78
|
+
* Returns the contained `Ok` value, or throws.
|
|
73
79
|
*
|
|
74
|
-
*
|
|
75
|
-
* const result = Ok(5);
|
|
76
|
-
* console.log(result.unwrap());
|
|
80
|
+
* @throws Error if this is `Err`
|
|
77
81
|
*/
|
|
78
82
|
unwrap(): T;
|
|
79
83
|
|
|
80
84
|
/**
|
|
81
|
-
* Returns the contained `
|
|
82
|
-
* the result is a `ResultOk`.
|
|
83
|
-
* @param msg The message to throw with if the result is Ok.
|
|
84
|
-
* @returns The contained `ResultErr` error.
|
|
85
|
+
* Returns the contained `Err` value, or throws with the provided message.
|
|
85
86
|
*
|
|
86
|
-
*
|
|
87
|
-
* const result = Err(new Error("Failure"));
|
|
88
|
-
* console.log(result.expect_err("Expected an error"));
|
|
87
|
+
* @throws Error with `msg` if this is `Ok`
|
|
89
88
|
*/
|
|
90
89
|
expect_err(msg: string): E;
|
|
91
90
|
|
|
92
91
|
/**
|
|
93
|
-
*
|
|
94
|
-
* @returns The `ResultErr` error.
|
|
95
|
-
* @throws Throws if the result is `ResultOk`.
|
|
92
|
+
* Returns the contained `Err` value, or throws.
|
|
96
93
|
*
|
|
97
|
-
*
|
|
98
|
-
* const result = Err(new Error("Failure"));
|
|
99
|
-
* console.log(result.unwrap_err());
|
|
94
|
+
* @throws Error if this is `Ok`
|
|
100
95
|
*/
|
|
101
96
|
unwrap_err(): E;
|
|
102
97
|
|
|
103
98
|
/**
|
|
104
|
-
*
|
|
105
|
-
* @returns The contained `ResultOk` value.
|
|
106
|
-
* @throws Throws if the result is `ResultErr`.
|
|
99
|
+
* Returns the contained `Ok` value. Identical to `unwrap()`.
|
|
107
100
|
*
|
|
108
|
-
*
|
|
109
|
-
* const result = Ok(5);
|
|
110
|
-
* console.log(result.into_ok());
|
|
101
|
+
* @throws Error if this is `Err`
|
|
111
102
|
*/
|
|
112
103
|
into_ok(): T;
|
|
113
104
|
|
|
114
105
|
/**
|
|
115
|
-
*
|
|
116
|
-
* @returns The contained `ResultErr` error.
|
|
117
|
-
* @throws Throws if the result is `ResultOk`.
|
|
106
|
+
* Returns the contained `Err` value. Identical to `unwrap_err()`.
|
|
118
107
|
*
|
|
119
|
-
*
|
|
120
|
-
* const result = Err(new Error("Failure"));
|
|
121
|
-
* console.log(result.into_err());
|
|
108
|
+
* @throws Error if this is `Ok`
|
|
122
109
|
*/
|
|
123
110
|
into_err(): E;
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Converts between different forms of `Result`, allowing the error type to be widened.
|
|
127
|
-
*
|
|
128
|
-
* If called on a `ResultOk<T, E>`, it will return a `Result<T, never>`, effectively discarding
|
|
129
|
-
* the error type. This is useful when you want to use the `Result` in a context that expects
|
|
130
|
-
* a `Result` with a specific error type, but you know that the `Result` is an `Ok` variant.
|
|
131
|
-
*
|
|
132
|
-
* If called on a `ResultErr<T, E>`, it will return a `Result<never, E>`, effectively discarding
|
|
133
|
-
* the value type. This is useful when you want to use the `Result` in a context that expects
|
|
134
|
-
* a `Result` with a specific value type, but you know that the `Result` is an `Err` variant.
|
|
135
|
-
*
|
|
136
|
-
* This is particularly useful when trying to forward a ResultErr returned by a function whose
|
|
137
|
-
* error type overlaps with the returned error type of the current function, but whose value type
|
|
138
|
-
* does not.
|
|
139
|
-
*
|
|
140
|
-
* Usage Example:
|
|
141
|
-
* const result: Result<number, Error> = Ok<number, Error>(5);
|
|
142
|
-
* const transmuted: Result<number, never> = result.transmute();
|
|
143
|
-
*
|
|
144
|
-
* const result: Result<number, Error> = Err<number, Error>(new Error("Failure"));
|
|
145
|
-
* const transmuted: Result<never, Error> = result.transmute();
|
|
146
|
-
*/
|
|
147
|
-
transmute(): Result<T, never> | Result<never, E>;
|
|
148
111
|
}
|
|
149
112
|
|
|
150
113
|
export interface IResultExt<T, E> extends IResultCore<T, E> {
|
|
151
114
|
/**
|
|
152
|
-
*
|
|
153
|
-
* @param f A predicate to apply to the contained value if the result is Ok.
|
|
154
|
-
* @returns true if the result is Ok and the predicate returns true, otherwise false.
|
|
155
|
-
*
|
|
156
|
-
* Usage Examples:
|
|
157
|
-
* const result = Ok(5);
|
|
158
|
-
* if (result.is_ok_and(x => x > 3)) {
|
|
159
|
-
* console.log("Result is Ok and greater than 3");
|
|
160
|
-
* }
|
|
161
|
-
*
|
|
162
|
-
* const result = Ok(2);
|
|
163
|
-
* if (!result.is_ok_and(x => x > 3)) {
|
|
164
|
-
* console.log("Result is not Ok or not greater than 3");
|
|
165
|
-
* }
|
|
115
|
+
* Returns `true` if `Ok` and the value satisfies the predicate.
|
|
166
116
|
*/
|
|
167
117
|
is_ok_and(f: (value: T) => boolean): boolean;
|
|
168
118
|
|
|
169
119
|
/**
|
|
170
|
-
*
|
|
171
|
-
* @param f A predicate to apply to the contained error if the result is Err.
|
|
172
|
-
* @returns true if the result is Err and the predicate returns true, otherwise false.
|
|
173
|
-
*
|
|
174
|
-
* Usage Examples:
|
|
175
|
-
* const result = Err(new Error("Network failure"));
|
|
176
|
-
* if (result.is_err_and(e => e.message.includes("Network"))) {
|
|
177
|
-
* console.log("Network error occurred");
|
|
178
|
-
* }
|
|
120
|
+
* Returns `true` if `Err` and the error satisfies the predicate.
|
|
179
121
|
*/
|
|
180
122
|
is_err_and(f: (value: E) => boolean): boolean;
|
|
181
123
|
|
|
182
124
|
/**
|
|
183
|
-
*
|
|
184
|
-
* @param fn A function to transform the Ok value.
|
|
185
|
-
* @returns A new Result where the Ok value has been transformed.
|
|
186
|
-
*
|
|
187
|
-
* Usage Example:
|
|
188
|
-
* const result = Ok(5);
|
|
189
|
-
* const mapped = result.map(x => x * 2);
|
|
190
|
-
*
|
|
191
|
-
* const result = Err("Error");
|
|
192
|
-
* const mapped = result.map(x => x * 2); // remains Err
|
|
125
|
+
* Maps a `Result<T, E>` to `Result<U, E>` by applying `fn` to the `Ok` value.
|
|
193
126
|
*/
|
|
194
127
|
map<U>(fn: (arg: T) => U): Result<U, E>;
|
|
195
128
|
|
|
196
129
|
/**
|
|
197
|
-
*
|
|
198
|
-
* @param defaultVal A default value to return if the result is Err.
|
|
199
|
-
* @param f A function to transform the Ok value.
|
|
200
|
-
* @returns The transformed Ok value or the default value.
|
|
201
|
-
*
|
|
202
|
-
* Usage Example:
|
|
203
|
-
* const result = Ok(5);
|
|
204
|
-
* const value = result.map_or(0, x => x * 2);
|
|
205
|
-
*
|
|
206
|
-
* const result = Err("Error");
|
|
207
|
-
* const value = result.map_or(0, x => x * 2); // 0
|
|
130
|
+
* Returns the provided default (if `Err`), or applies `fn` to the `Ok` value.
|
|
208
131
|
*/
|
|
209
132
|
map_or<U>(defaultVal: U, f: (arg: T) => U): U;
|
|
210
133
|
|
|
211
134
|
/**
|
|
212
|
-
*
|
|
213
|
-
* @param defaultFunc A function to compute a default value if the result is Err.
|
|
214
|
-
* @param f A function to transform the Ok value.
|
|
215
|
-
* @returns The transformed Ok value or the computed default value.
|
|
216
|
-
*
|
|
217
|
-
* Usage Example:
|
|
218
|
-
* const result = Ok(5);
|
|
219
|
-
* const value = result.map_or_else(() => 0, x => x * 2);
|
|
220
|
-
*
|
|
221
|
-
* const result = Err("Error");
|
|
222
|
-
* const value = result.map_or_else(() => 0, x => x * 2); // 0
|
|
135
|
+
* Computes a default (if `Err`), or applies `fn` to the `Ok` value.
|
|
223
136
|
*/
|
|
224
137
|
map_or_else<U>(defaultFunc: (err: E) => U, f: (arg: T) => U): U;
|
|
225
138
|
|
|
226
139
|
/**
|
|
227
|
-
* Maps a `Result<T, E>` to `Result<T, U>` by applying
|
|
228
|
-
* @param fn A function to transform the Err value.
|
|
229
|
-
* @returns A new Result where the Err has been transformed.
|
|
230
|
-
*
|
|
231
|
-
* Usage Example:
|
|
232
|
-
* const result = Err("Error");
|
|
233
|
-
* const mappedErr = result.map_err(e => new Error(e));
|
|
140
|
+
* Maps a `Result<T, E>` to `Result<T, U>` by applying `fn` to the `Err` value.
|
|
234
141
|
*/
|
|
235
142
|
map_err<U>(fn: (arg: E) => U): Result<T, U>;
|
|
236
143
|
|
|
237
144
|
/**
|
|
238
|
-
*
|
|
239
|
-
* @param f A function to apply to the Ok value.
|
|
240
|
-
* @returns The original Result.
|
|
241
|
-
*
|
|
242
|
-
* Usage Example:
|
|
243
|
-
* const result = Ok(5);
|
|
244
|
-
* result.inspect(x => console.log(`Value: ${x}`));
|
|
145
|
+
* Calls `fn` with the `Ok` value if present, then returns the original result.
|
|
245
146
|
*/
|
|
246
|
-
inspect(f: (val: T) => void):
|
|
147
|
+
inspect(f: (val: T) => void): this;
|
|
247
148
|
|
|
248
149
|
/**
|
|
249
|
-
*
|
|
250
|
-
* @param f A function to apply to the Err value.
|
|
251
|
-
* @returns The original Result.
|
|
252
|
-
*
|
|
253
|
-
* Usage Example:
|
|
254
|
-
* const result = Err("Error");
|
|
255
|
-
* result.inspect_err(e => console.log(`Error: ${e}`));
|
|
150
|
+
* Calls `fn` with the `Err` value if present, then returns the original result.
|
|
256
151
|
*/
|
|
257
|
-
inspect_err(f: (val: E) => void):
|
|
152
|
+
inspect_err(f: (val: E) => void): this;
|
|
258
153
|
|
|
259
154
|
/**
|
|
260
|
-
* Returns `res` if
|
|
261
|
-
* @param res The result to return if `self` is Ok.
|
|
262
|
-
* @returns Either `res` or the original Err.
|
|
263
|
-
*
|
|
264
|
-
* Usage Example:
|
|
265
|
-
* const result = Ok(5);
|
|
266
|
-
* const other = Ok("Hello");
|
|
267
|
-
* const finalResult = result.and(other); // Ok("Hello")
|
|
155
|
+
* Returns `res` if `Ok`, otherwise returns the `Err` value of `self`.
|
|
268
156
|
*/
|
|
269
157
|
and<U>(res: Result<U, E>): Result<U, E>;
|
|
270
158
|
|
|
271
159
|
/**
|
|
272
|
-
* Calls `fn` if
|
|
273
|
-
*
|
|
274
|
-
* @returns The result of `fn` if the original result is Ok, otherwise the Err.
|
|
275
|
-
*
|
|
276
|
-
* Usage Example:
|
|
277
|
-
* const result = Ok(5);
|
|
278
|
-
* const finalResult = result.and_then(x => Ok(x * 2)); // Ok(10)
|
|
160
|
+
* Calls `fn` if `Ok`, otherwise returns the `Err` value of `self`.
|
|
161
|
+
* This is the monadic bind operation (flatMap).
|
|
279
162
|
*/
|
|
280
163
|
and_then<U>(fn: (arg: T) => Result<U, E>): Result<U, E>;
|
|
281
164
|
|
|
282
165
|
/**
|
|
283
|
-
* Returns `res` if
|
|
284
|
-
* @param res The result to return if `self` is Err.
|
|
285
|
-
* @returns Either `res` or the original Ok.
|
|
286
|
-
*
|
|
287
|
-
* Usage Example:
|
|
288
|
-
* const result = Err("Error");
|
|
289
|
-
* const other = Ok(5);
|
|
290
|
-
* const finalResult = result.or(other); // Ok(5)
|
|
166
|
+
* Returns `res` if `Err`, otherwise returns the `Ok` value of `self`.
|
|
291
167
|
*/
|
|
292
|
-
or<
|
|
168
|
+
or<F>(res: Result<T, F>): Result<T, F>;
|
|
293
169
|
|
|
294
170
|
/**
|
|
295
|
-
* Calls `fn` if
|
|
296
|
-
* @param fn A function to apply to the Err value.
|
|
297
|
-
* @returns The result of `fn` if the original result is Err, otherwise the Ok.
|
|
298
|
-
*
|
|
299
|
-
* Usage Example:
|
|
300
|
-
* const result = Err("Error");
|
|
301
|
-
* const finalResult = result.or_else(e => Ok(`Handled ${e}`)); // Ok("Handled Error")
|
|
171
|
+
* Calls `fn` if `Err`, otherwise returns the `Ok` value of `self`.
|
|
302
172
|
*/
|
|
303
|
-
or_else<
|
|
173
|
+
or_else<F>(fn: (arg: E) => Result<T, F>): Result<T, F>;
|
|
304
174
|
|
|
305
175
|
/**
|
|
306
|
-
* Returns the contained Ok value or
|
|
307
|
-
* @param defaultVal The default value to return if the result is Err.
|
|
308
|
-
* @returns The Ok value or the default.
|
|
309
|
-
*
|
|
310
|
-
* Usage Example:
|
|
311
|
-
* const result = Ok(5);
|
|
312
|
-
* console.log(result.unwrap_or(0)); // 5
|
|
313
|
-
*
|
|
314
|
-
* const result = Err("Error");
|
|
315
|
-
* console.log(result.unwrap_or(0)); // 0
|
|
176
|
+
* Returns the contained `Ok` value or the provided default.
|
|
316
177
|
*/
|
|
317
178
|
unwrap_or(defaultVal: T): T;
|
|
318
179
|
|
|
319
180
|
/**
|
|
320
|
-
* Returns the contained Ok value or computes it from
|
|
321
|
-
* @param fn A function to compute the default value if the result is Err.
|
|
322
|
-
* @returns The Ok value or the computed one.
|
|
323
|
-
*
|
|
324
|
-
* Usage Example:
|
|
325
|
-
* const result = Err("Error");
|
|
326
|
-
* console.log(result.unwrap_or_else(() => 5)); // 5
|
|
181
|
+
* Returns the contained `Ok` value or computes it from `fn`.
|
|
327
182
|
*/
|
|
328
183
|
unwrap_or_else(fn: (arg: E) => T): T;
|
|
329
184
|
}
|
|
330
185
|
|
|
331
|
-
type UnwrapResult<T> = T extends Result<infer U, any> ? U : T;
|
|
332
|
-
|
|
333
186
|
export interface IResultIteration<T, E> extends IResultCore<T, E> {
|
|
334
187
|
/**
|
|
335
|
-
* Returns an iterator over the
|
|
336
|
-
*
|
|
337
|
-
*
|
|
338
|
-
* Usage Example:
|
|
339
|
-
* const okResult = Ok(5);
|
|
340
|
-
* for (const value of okResult.iter()) {
|
|
341
|
-
* console.log(value); // prints 5
|
|
342
|
-
* }
|
|
343
|
-
*
|
|
344
|
-
* const errResult = Err(new Error("error"));
|
|
345
|
-
* for (const value of errResult.iter()) {
|
|
346
|
-
* // This block will not be executed.
|
|
347
|
-
* }
|
|
188
|
+
* Returns an iterator over the possibly contained `Ok` value.
|
|
189
|
+
* Yields one element if `Ok`, zero if `Err`.
|
|
348
190
|
*/
|
|
349
191
|
iter(): IterableIterator<T>;
|
|
350
192
|
|
|
351
193
|
/**
|
|
352
|
-
* Flattens a
|
|
353
|
-
* @returns A single-layer `Result`, by stripping one layer of `Result` container.
|
|
194
|
+
* Flattens a `Result<Result<U, E2>, E>` into `Result<U, E | E2>`.
|
|
354
195
|
*
|
|
355
|
-
*
|
|
356
|
-
|
|
357
|
-
|
|
196
|
+
* If `T` is not a `Result`, returns `Result<T, E>` unchanged.
|
|
197
|
+
*/
|
|
198
|
+
flatten(): FlattenResult<T, E>;
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Transposes a `Result` of an `Option` into an `Option` of a `Result`.
|
|
202
|
+
*
|
|
203
|
+
* - `Ok(None)` → `None`
|
|
204
|
+
* - `Ok(Some(v))` → `Some(Ok(v))`
|
|
205
|
+
* - `Err(e)` → `Some(Err(e))`
|
|
206
|
+
*
|
|
207
|
+
* @example
|
|
208
|
+
* ```typescript
|
|
209
|
+
* Ok(Some(5)).transpose() // Some(Ok(5))
|
|
210
|
+
* Ok(None()).transpose() // None
|
|
211
|
+
* Err("e").transpose() // Some(Err("e"))
|
|
212
|
+
* ```
|
|
213
|
+
*/
|
|
214
|
+
transpose(): T extends { _tag: 'Some'; value: infer U }
|
|
215
|
+
? { _tag: 'Some'; value: Result<U, E> }
|
|
216
|
+
: T extends { _tag: 'None' }
|
|
217
|
+
? { _tag: 'None' }
|
|
218
|
+
: { _tag: 'Some' | 'None'; value?: Result<unknown, E> };
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Methods specific to `ResultOk` that provide more precise types.
|
|
223
|
+
*/
|
|
224
|
+
export interface IResultOkSpecific<T, E> {
|
|
225
|
+
/**
|
|
226
|
+
* Type-safe transmute that narrows the error type to `never`.
|
|
358
227
|
*
|
|
359
|
-
*
|
|
360
|
-
* const flattenedError = nestedErr.flatten(); // Results in Err(new Error("error"))
|
|
228
|
+
* Since this is `Ok`, there's no error, so `E` can safely become `never`.
|
|
361
229
|
*/
|
|
362
|
-
|
|
230
|
+
transmute(): ResultOk<T, never>;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Methods specific to `ResultErr` that provide more precise types.
|
|
235
|
+
*/
|
|
236
|
+
export interface IResultErrSpecific<T, E> {
|
|
237
|
+
/**
|
|
238
|
+
* Type-safe transmute that narrows the value type to `never`.
|
|
239
|
+
*
|
|
240
|
+
* Since this is `Err`, there's no value, so `T` can safely become `never`.
|
|
241
|
+
*/
|
|
242
|
+
transmute(): ResultErr<never, E>;
|
|
363
243
|
}
|
|
364
244
|
|
|
365
245
|
export interface IResult<T, E> extends
|
|
366
246
|
IResultCore<T, E>,
|
|
367
247
|
IResultExt<T, E>,
|
|
368
|
-
IResultIteration<T, E> {
|
|
248
|
+
IResultIteration<T, E> {
|
|
249
|
+
/**
|
|
250
|
+
* Converts between different Result types by narrowing phantom types.
|
|
251
|
+
*
|
|
252
|
+
* - On `Ok<T, E>`: returns `Ok<T, never>` (error type becomes `never`)
|
|
253
|
+
* - On `Err<T, E>`: returns `Err<never, E>` (value type becomes `never`)
|
|
254
|
+
*/
|
|
255
|
+
transmute(): ResultOk<T, never> | ResultErr<never, E>;
|
|
256
|
+
}
|
|
369
257
|
|
|
370
|
-
|
|
258
|
+
// ============================================================================
|
|
259
|
+
// Type Guards
|
|
260
|
+
// ============================================================================
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Type guard to check if a value is `ResultOk`.
|
|
264
|
+
*/
|
|
265
|
+
export const isResultOk = <T, E>(val: Result<T, E>): val is ResultOk<T, E> => {
|
|
371
266
|
return val instanceof ResultOk;
|
|
372
|
-
}
|
|
267
|
+
};
|
|
373
268
|
|
|
374
|
-
|
|
269
|
+
/**
|
|
270
|
+
* Type guard to check if a value is `ResultErr`.
|
|
271
|
+
*/
|
|
272
|
+
export const isResultErr = <T, E>(val: Result<T, E>): val is ResultErr<T, E> => {
|
|
375
273
|
return val instanceof ResultErr;
|
|
376
|
-
}
|
|
274
|
+
};
|
|
377
275
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
private readonly _T: T;
|
|
382
|
-
// @ts-ignore
|
|
383
|
-
private readonly _E: E;
|
|
276
|
+
// ============================================================================
|
|
277
|
+
// ResultOk Implementation
|
|
278
|
+
// ============================================================================
|
|
384
279
|
|
|
385
|
-
|
|
386
|
-
|
|
280
|
+
/**
|
|
281
|
+
* The `Ok` variant of `Result<T, E>`, representing success with a value of type `T`.
|
|
282
|
+
*
|
|
283
|
+
* Uses branded typing for nominal type safety.
|
|
284
|
+
*
|
|
285
|
+
* @typeParam T - The success value type
|
|
286
|
+
* @typeParam E - The error type (phantom - not used at runtime in Ok)
|
|
287
|
+
*/
|
|
288
|
+
export class ResultOk<out T, out E = never> implements IResult<T, E>, IResultOkSpecific<T, E> {
|
|
289
|
+
/** Brand for nominal typing - ensures ResultOk is distinct from ResultErr */
|
|
290
|
+
declare readonly [OkBrand]: T;
|
|
291
|
+
|
|
292
|
+
/** Discriminant tag for runtime type checking */
|
|
293
|
+
readonly _tag = 'Ok' as const;
|
|
387
294
|
|
|
295
|
+
constructor(readonly value: T) {}
|
|
296
|
+
|
|
297
|
+
// Type guards
|
|
388
298
|
is_ok(): this is ResultOk<T, E> {
|
|
389
299
|
return true;
|
|
390
300
|
}
|
|
391
301
|
|
|
392
|
-
is_err(): this is
|
|
302
|
+
is_err(): this is ResultErr<T, E> {
|
|
393
303
|
return false;
|
|
394
304
|
}
|
|
395
305
|
|
|
@@ -397,10 +307,11 @@ export class ResultOk<T, E> implements IResult<T, E> {
|
|
|
397
307
|
return f(this.value);
|
|
398
308
|
}
|
|
399
309
|
|
|
400
|
-
is_err_and(_f: (value: E) => boolean):
|
|
310
|
+
is_err_and(_f: (value: E) => boolean): false {
|
|
401
311
|
return false;
|
|
402
312
|
}
|
|
403
313
|
|
|
314
|
+
// Conversion to Option
|
|
404
315
|
ok(): Option<T> {
|
|
405
316
|
return Some(this.value);
|
|
406
317
|
}
|
|
@@ -409,8 +320,9 @@ export class ResultOk<T, E> implements IResult<T, E> {
|
|
|
409
320
|
return None();
|
|
410
321
|
}
|
|
411
322
|
|
|
412
|
-
|
|
413
|
-
|
|
323
|
+
// Transformations
|
|
324
|
+
map<U>(fn: (arg: T) => U): ResultOk<U, E> {
|
|
325
|
+
return new ResultOk(fn(this.value));
|
|
414
326
|
}
|
|
415
327
|
|
|
416
328
|
map_or<U>(_d: U, f: (arg: T) => U): U {
|
|
@@ -421,24 +333,31 @@ export class ResultOk<T, E> implements IResult<T, E> {
|
|
|
421
333
|
return f(this.value);
|
|
422
334
|
}
|
|
423
335
|
|
|
424
|
-
|
|
425
|
-
|
|
336
|
+
/**
|
|
337
|
+
* On Ok, map_err is a no-op that changes only the error type parameter.
|
|
338
|
+
* We construct a new ResultOk with the same value but updated type parameter.
|
|
339
|
+
*/
|
|
340
|
+
map_err<U>(_fn: (arg: E) => U): ResultOk<T, U> {
|
|
341
|
+
// Type-safe: we're Ok, so E is phantom. Creating new instance preserves type safety.
|
|
342
|
+
return new ResultOk<T, U>(this.value);
|
|
426
343
|
}
|
|
427
344
|
|
|
428
|
-
|
|
345
|
+
// Inspection
|
|
346
|
+
inspect(f: (val: T) => void): this {
|
|
429
347
|
f(this.value);
|
|
430
|
-
|
|
431
348
|
return this;
|
|
432
349
|
}
|
|
433
350
|
|
|
434
|
-
inspect_err(_f: (val: E) => void):
|
|
351
|
+
inspect_err(_f: (val: E) => void): this {
|
|
435
352
|
return this;
|
|
436
353
|
}
|
|
437
354
|
|
|
355
|
+
// Iteration
|
|
438
356
|
iter(): IterableIterator<T> {
|
|
439
357
|
return [this.value][Symbol.iterator]();
|
|
440
358
|
}
|
|
441
359
|
|
|
360
|
+
// Unwrapping
|
|
442
361
|
expect(_msg: string): T {
|
|
443
362
|
return this.value;
|
|
444
363
|
}
|
|
@@ -447,11 +366,7 @@ export class ResultOk<T, E> implements IResult<T, E> {
|
|
|
447
366
|
return this.value;
|
|
448
367
|
}
|
|
449
368
|
|
|
450
|
-
|
|
451
|
-
// ! not implemented
|
|
452
|
-
//}
|
|
453
|
-
|
|
454
|
-
expect_err(msg: string): E {
|
|
369
|
+
expect_err(msg: string): never {
|
|
455
370
|
throw new Error(msg);
|
|
456
371
|
}
|
|
457
372
|
|
|
@@ -459,6 +374,7 @@ export class ResultOk<T, E> implements IResult<T, E> {
|
|
|
459
374
|
throw new Error('Called Result.unwrap_err() on an Ok value: ' + this.value);
|
|
460
375
|
}
|
|
461
376
|
|
|
377
|
+
// Combinators
|
|
462
378
|
and<U>(res: Result<U, E>): Result<U, E> {
|
|
463
379
|
return res;
|
|
464
380
|
}
|
|
@@ -467,14 +383,21 @@ export class ResultOk<T, E> implements IResult<T, E> {
|
|
|
467
383
|
return fn(this.value);
|
|
468
384
|
}
|
|
469
385
|
|
|
470
|
-
|
|
471
|
-
|
|
386
|
+
/**
|
|
387
|
+
* On Ok, `or` returns self. We construct a new ResultOk with updated error type.
|
|
388
|
+
*/
|
|
389
|
+
or<F>(_res: Result<T, F>): ResultOk<T, F> {
|
|
390
|
+
return new ResultOk<T, F>(this.value);
|
|
472
391
|
}
|
|
473
392
|
|
|
474
|
-
|
|
475
|
-
|
|
393
|
+
/**
|
|
394
|
+
* On Ok, `or_else` returns self. We construct a new ResultOk with updated error type.
|
|
395
|
+
*/
|
|
396
|
+
or_else<F>(_fn: (arg: E) => Result<T, F>): ResultOk<T, F> {
|
|
397
|
+
return new ResultOk<T, F>(this.value);
|
|
476
398
|
}
|
|
477
399
|
|
|
400
|
+
// Default values
|
|
478
401
|
unwrap_or(_optb: T): T {
|
|
479
402
|
return this.value;
|
|
480
403
|
}
|
|
@@ -483,16 +406,16 @@ export class ResultOk<T, E> implements IResult<T, E> {
|
|
|
483
406
|
return this.value;
|
|
484
407
|
}
|
|
485
408
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
// but it's here to satisfy TypeScript's type checker.
|
|
492
|
-
return new ResultOk<UnwrapResult<T>, E>(this.value as UnwrapResult<T>);
|
|
409
|
+
// Flattening
|
|
410
|
+
flatten(): FlattenResult<T, E> {
|
|
411
|
+
const val = this.value;
|
|
412
|
+
if (val instanceof ResultOk || val instanceof ResultErr) {
|
|
413
|
+
return val as FlattenResult<T, E>;
|
|
493
414
|
}
|
|
415
|
+
return this as unknown as FlattenResult<T, E>;
|
|
494
416
|
}
|
|
495
417
|
|
|
418
|
+
// Type narrowing
|
|
496
419
|
into_ok(): T {
|
|
497
420
|
return this.value;
|
|
498
421
|
}
|
|
@@ -501,22 +424,49 @@ export class ResultOk<T, E> implements IResult<T, E> {
|
|
|
501
424
|
throw new Error('Called Result.into_err() on an Ok value: ' + this.value);
|
|
502
425
|
}
|
|
503
426
|
|
|
504
|
-
|
|
505
|
-
|
|
427
|
+
/**
|
|
428
|
+
* Transmutes to Ok<T, never>, proving there's no error.
|
|
429
|
+
*/
|
|
430
|
+
transmute(): ResultOk<T, never> {
|
|
431
|
+
return new ResultOk<T, never>(this.value);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* Transposes Ok(Option<U>) into Option<Result<U, E>>.
|
|
436
|
+
*/
|
|
437
|
+
transpose(): any {
|
|
438
|
+
const option = this.value as { _tag: 'Some' | 'None'; value?: unknown; is_some?(): boolean };
|
|
439
|
+
if (option._tag === 'Some' || (option.is_some && option.is_some())) {
|
|
440
|
+
return Some(new ResultOk(option.value));
|
|
441
|
+
} else {
|
|
442
|
+
return None();
|
|
443
|
+
}
|
|
506
444
|
}
|
|
507
445
|
}
|
|
508
446
|
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
private readonly _T: T;
|
|
513
|
-
// @ts-ignore
|
|
514
|
-
private readonly _E: E;
|
|
447
|
+
// ============================================================================
|
|
448
|
+
// ResultErr Implementation
|
|
449
|
+
// ============================================================================
|
|
515
450
|
|
|
516
|
-
|
|
517
|
-
|
|
451
|
+
/**
|
|
452
|
+
* The `Err` variant of `Result<T, E>`, representing failure with an error of type `E`.
|
|
453
|
+
*
|
|
454
|
+
* Uses branded typing for nominal type safety.
|
|
455
|
+
*
|
|
456
|
+
* @typeParam T - The success type (phantom - not used at runtime in Err)
|
|
457
|
+
* @typeParam E - The error value type
|
|
458
|
+
*/
|
|
459
|
+
export class ResultErr<out T = never, out E = unknown> implements IResult<T, E>, IResultErrSpecific<T, E> {
|
|
460
|
+
/** Brand for nominal typing - ensures ResultErr is distinct from ResultOk */
|
|
461
|
+
declare readonly [ErrBrand]: E;
|
|
518
462
|
|
|
519
|
-
|
|
463
|
+
/** Discriminant tag for runtime type checking */
|
|
464
|
+
readonly _tag = 'Err' as const;
|
|
465
|
+
|
|
466
|
+
constructor(readonly value: E) {}
|
|
467
|
+
|
|
468
|
+
// Type guards
|
|
469
|
+
is_ok(): this is ResultOk<T, E> {
|
|
520
470
|
return false;
|
|
521
471
|
}
|
|
522
472
|
|
|
@@ -524,7 +474,7 @@ export class ResultErr<T, E> implements IResult<T, E> {
|
|
|
524
474
|
return true;
|
|
525
475
|
}
|
|
526
476
|
|
|
527
|
-
is_ok_and(_f: (value: T) => boolean):
|
|
477
|
+
is_ok_and(_f: (value: T) => boolean): false {
|
|
528
478
|
return false;
|
|
529
479
|
}
|
|
530
480
|
|
|
@@ -532,6 +482,7 @@ export class ResultErr<T, E> implements IResult<T, E> {
|
|
|
532
482
|
return f(this.value);
|
|
533
483
|
}
|
|
534
484
|
|
|
485
|
+
// Conversion to Option
|
|
535
486
|
ok(): Option<T> {
|
|
536
487
|
return None();
|
|
537
488
|
}
|
|
@@ -540,8 +491,12 @@ export class ResultErr<T, E> implements IResult<T, E> {
|
|
|
540
491
|
return Some(this.value);
|
|
541
492
|
}
|
|
542
493
|
|
|
543
|
-
|
|
544
|
-
|
|
494
|
+
// Transformations
|
|
495
|
+
/**
|
|
496
|
+
* On Err, map is a no-op that changes only the value type parameter.
|
|
497
|
+
*/
|
|
498
|
+
map<U>(_fn: (arg: T) => U): ResultErr<U, E> {
|
|
499
|
+
return new ResultErr<U, E>(this.value);
|
|
545
500
|
}
|
|
546
501
|
|
|
547
502
|
map_or<U>(d: U, _f: (arg: T) => U): U {
|
|
@@ -552,23 +507,26 @@ export class ResultErr<T, E> implements IResult<T, E> {
|
|
|
552
507
|
return d(this.value);
|
|
553
508
|
}
|
|
554
509
|
|
|
555
|
-
map_err<U>(fn: (arg: E) => U):
|
|
556
|
-
return new ResultErr
|
|
510
|
+
map_err<U>(fn: (arg: E) => U): ResultErr<T, U> {
|
|
511
|
+
return new ResultErr(fn(this.value));
|
|
557
512
|
}
|
|
558
513
|
|
|
559
|
-
|
|
514
|
+
// Inspection
|
|
515
|
+
inspect(_f: (val: T) => void): this {
|
|
560
516
|
return this;
|
|
561
517
|
}
|
|
562
518
|
|
|
563
|
-
inspect_err(f: (val: E) => void):
|
|
519
|
+
inspect_err(f: (val: E) => void): this {
|
|
564
520
|
f(this.value);
|
|
565
521
|
return this;
|
|
566
522
|
}
|
|
567
523
|
|
|
524
|
+
// Iteration
|
|
568
525
|
iter(): IterableIterator<T> {
|
|
569
526
|
return [][Symbol.iterator]();
|
|
570
527
|
}
|
|
571
528
|
|
|
529
|
+
// Unwrapping
|
|
572
530
|
expect(msg: string): never {
|
|
573
531
|
throw new Error(msg);
|
|
574
532
|
}
|
|
@@ -577,10 +535,6 @@ export class ResultErr<T, E> implements IResult<T, E> {
|
|
|
577
535
|
throw new Error('Called Result.unwrap() on an Err value: ' + this.value);
|
|
578
536
|
}
|
|
579
537
|
|
|
580
|
-
//unwrap_or_default(): never {
|
|
581
|
-
// // ! not implemented
|
|
582
|
-
//}
|
|
583
|
-
|
|
584
538
|
expect_err(_msg: string): E {
|
|
585
539
|
return this.value;
|
|
586
540
|
}
|
|
@@ -589,22 +543,30 @@ export class ResultErr<T, E> implements IResult<T, E> {
|
|
|
589
543
|
return this.value;
|
|
590
544
|
}
|
|
591
545
|
|
|
592
|
-
|
|
593
|
-
|
|
546
|
+
// Combinators
|
|
547
|
+
/**
|
|
548
|
+
* On Err, `and` returns self. We construct a new ResultErr with updated value type.
|
|
549
|
+
*/
|
|
550
|
+
and<U>(_res: Result<U, E>): ResultErr<U, E> {
|
|
551
|
+
return new ResultErr<U, E>(this.value);
|
|
594
552
|
}
|
|
595
553
|
|
|
596
|
-
|
|
597
|
-
|
|
554
|
+
/**
|
|
555
|
+
* On Err, `and_then` returns self. We construct a new ResultErr with updated value type.
|
|
556
|
+
*/
|
|
557
|
+
and_then<U>(_fn: (arg: T) => Result<U, E>): ResultErr<U, E> {
|
|
558
|
+
return new ResultErr<U, E>(this.value);
|
|
598
559
|
}
|
|
599
560
|
|
|
600
|
-
or<
|
|
561
|
+
or<F>(res: Result<T, F>): Result<T, F> {
|
|
601
562
|
return res;
|
|
602
563
|
}
|
|
603
564
|
|
|
604
|
-
or_else<
|
|
565
|
+
or_else<F>(fn: (arg: E) => Result<T, F>): Result<T, F> {
|
|
605
566
|
return fn(this.value);
|
|
606
567
|
}
|
|
607
568
|
|
|
569
|
+
// Default values
|
|
608
570
|
unwrap_or(optb: T): T {
|
|
609
571
|
return optb;
|
|
610
572
|
}
|
|
@@ -613,11 +575,13 @@ export class ResultErr<T, E> implements IResult<T, E> {
|
|
|
613
575
|
return fn(this.value);
|
|
614
576
|
}
|
|
615
577
|
|
|
616
|
-
|
|
617
|
-
|
|
578
|
+
// Flattening
|
|
579
|
+
flatten(): FlattenResult<T, E> {
|
|
580
|
+
return new ResultErr<UnwrapOk<T>, E>(this.value) as FlattenResult<T, E>;
|
|
618
581
|
}
|
|
619
582
|
|
|
620
|
-
|
|
583
|
+
// Type narrowing
|
|
584
|
+
into_ok(): never {
|
|
621
585
|
throw new Error('Called Result.into_ok() on an Err value: ' + this.value);
|
|
622
586
|
}
|
|
623
587
|
|
|
@@ -625,37 +589,151 @@ export class ResultErr<T, E> implements IResult<T, E> {
|
|
|
625
589
|
return this.value;
|
|
626
590
|
}
|
|
627
591
|
|
|
628
|
-
|
|
629
|
-
|
|
592
|
+
/**
|
|
593
|
+
* Transmutes to Err<never, E>, proving there's no value.
|
|
594
|
+
*/
|
|
595
|
+
transmute(): ResultErr<never, E> {
|
|
596
|
+
return new ResultErr<never, E>(this.value);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
/**
|
|
600
|
+
* Transposes Err(e) into Some(Err(e)).
|
|
601
|
+
* For Err, we always return Some(Err(e)) regardless of the expected Option type.
|
|
602
|
+
*/
|
|
603
|
+
transpose(): any {
|
|
604
|
+
return Some(new ResultErr(this.value));
|
|
630
605
|
}
|
|
631
606
|
}
|
|
632
|
-
|
|
633
|
-
|
|
607
|
+
|
|
608
|
+
// ============================================================================
|
|
609
|
+
// Factory Functions
|
|
610
|
+
// ============================================================================
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* Creates an `Ok` result containing the given value.
|
|
614
|
+
*
|
|
615
|
+
* The error type defaults to `never`, indicating this Result cannot be an Err.
|
|
616
|
+
* This enables type inference to work correctly in chains.
|
|
617
|
+
*
|
|
618
|
+
* @example
|
|
619
|
+
* const result = Ok(42); // Result<number, never>
|
|
620
|
+
* const mapped = result.map(x => x * 2); // Result<number, never>
|
|
621
|
+
*/
|
|
622
|
+
export const Ok = <T>(val: T): ResultOk<T, never> => {
|
|
623
|
+
return new ResultOk<T, never>(val);
|
|
634
624
|
};
|
|
635
625
|
|
|
636
|
-
|
|
637
|
-
|
|
626
|
+
/**
|
|
627
|
+
* Creates an `Err` result containing the given error.
|
|
628
|
+
*
|
|
629
|
+
* The value type defaults to `never`, indicating this Result cannot be Ok.
|
|
630
|
+
* This enables type inference to work correctly in chains.
|
|
631
|
+
*
|
|
632
|
+
* @example
|
|
633
|
+
* const result = Err(new Error("failed")); // Result<never, Error>
|
|
634
|
+
* const handled = result.or(Ok(0)); // Result<number, never>
|
|
635
|
+
*/
|
|
636
|
+
export const Err = <E>(val: E): ResultErr<never, E> => {
|
|
637
|
+
return new ResultErr<never, E>(val);
|
|
638
638
|
};
|
|
639
639
|
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
640
|
+
// ============================================================================
|
|
641
|
+
// Utility Functions
|
|
642
|
+
// ============================================================================
|
|
643
|
+
|
|
644
|
+
/**
|
|
645
|
+
* Executes a function and wraps its result in a `Result`.
|
|
646
|
+
*
|
|
647
|
+
* If the function succeeds, returns `Ok(value)`.
|
|
648
|
+
* If it throws, returns `Err(error)`.
|
|
649
|
+
*
|
|
650
|
+
* @typeParam T - The return type of the function
|
|
651
|
+
* @typeParam E - The error type (defaults to Error)
|
|
652
|
+
*
|
|
653
|
+
* @example
|
|
654
|
+
* const result = try_catch(() => JSON.parse(jsonString));
|
|
655
|
+
* // Result<unknown, Error>
|
|
656
|
+
*/
|
|
657
|
+
export const try_catch = <T, E = Error>(fn: () => T): Result<T, E> => {
|
|
658
|
+
try {
|
|
659
|
+
return Ok(fn()) as Result<T, E>;
|
|
660
|
+
} catch (error: unknown) {
|
|
661
|
+
return Err(error as E) as Result<T, E>;
|
|
662
|
+
}
|
|
663
|
+
};
|
|
664
|
+
|
|
665
|
+
/**
|
|
666
|
+
* Converts a Promise to a Result wrapped in a Promise.
|
|
667
|
+
*
|
|
668
|
+
* If the promise resolves, returns `Ok(value)`.
|
|
669
|
+
* If it rejects, returns `Err(error)`.
|
|
670
|
+
*
|
|
671
|
+
* @typeParam T - The resolved value type
|
|
672
|
+
* @typeParam E - The error type (defaults to Error)
|
|
673
|
+
*
|
|
674
|
+
* @example
|
|
675
|
+
* const result = await result_from_promise(fetch('/api/data'));
|
|
676
|
+
* // Result<Response, Error>
|
|
677
|
+
*/
|
|
678
|
+
export const result_from_promise = async <T, E = Error>(
|
|
679
|
+
val: Promise<T>,
|
|
680
|
+
): Promise<Result<T, E>> => {
|
|
681
|
+
try {
|
|
682
|
+
return Ok(await val) as Result<T, E>;
|
|
683
|
+
} catch (error: unknown) {
|
|
684
|
+
return Err(error as E) as Result<T, E>;
|
|
685
|
+
}
|
|
686
|
+
};
|
|
687
|
+
|
|
688
|
+
// ============================================================================
|
|
689
|
+
// Advanced Type Utilities
|
|
690
|
+
// ============================================================================
|
|
691
|
+
|
|
692
|
+
/**
|
|
693
|
+
* Combines multiple Results into a single Result containing an array.
|
|
694
|
+
*
|
|
695
|
+
* If all Results are Ok, returns Ok with array of values.
|
|
696
|
+
* If any Result is Err, returns the first Err encountered.
|
|
697
|
+
*
|
|
698
|
+
* @example
|
|
699
|
+
* const results = collect([Ok(1), Ok(2), Ok(3)]);
|
|
700
|
+
* // Result<[number, number, number], never>
|
|
701
|
+
*/
|
|
702
|
+
export function collect<T extends readonly Result<any, any>[]>(
|
|
703
|
+
results: T
|
|
704
|
+
): Result<
|
|
705
|
+
{ [K in keyof T]: T[K] extends Result<infer U, any> ? U : never },
|
|
706
|
+
{ [K in keyof T]: T[K] extends Result<any, infer E> ? E : never }[number]
|
|
707
|
+
> {
|
|
708
|
+
const values: any[] = [];
|
|
709
|
+
for (const result of results) {
|
|
710
|
+
if (result.is_err()) {
|
|
711
|
+
return result as any;
|
|
660
712
|
}
|
|
661
|
-
|
|
713
|
+
values.push(result.value);
|
|
714
|
+
}
|
|
715
|
+
return Ok(values) as any;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
/**
|
|
719
|
+
* Type-safe match expression for Result.
|
|
720
|
+
*
|
|
721
|
+
* @example
|
|
722
|
+
* const message = matchResult(result, {
|
|
723
|
+
* Ok: (value) => `Success: ${value}`,
|
|
724
|
+
* Err: (error) => `Failed: ${error.message}`,
|
|
725
|
+
* });
|
|
726
|
+
*/
|
|
727
|
+
export function matchResult<T, E, R>(
|
|
728
|
+
result: Result<T, E>,
|
|
729
|
+
handlers: {
|
|
730
|
+
Ok: (value: T) => R;
|
|
731
|
+
Err: (error: E) => R;
|
|
732
|
+
}
|
|
733
|
+
): R {
|
|
734
|
+
if (result.is_ok()) {
|
|
735
|
+
return handlers.Ok(result.value);
|
|
736
|
+
} else {
|
|
737
|
+
return handlers.Err(result.value);
|
|
738
|
+
}
|
|
739
|
+
}
|