nalloc 0.0.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/README.md +282 -0
- package/build/devtools.cjs +79 -0
- package/build/devtools.cjs.map +1 -0
- package/build/devtools.d.ts +82 -0
- package/build/devtools.js +43 -0
- package/build/devtools.js.map +1 -0
- package/build/index.cjs +76 -0
- package/build/index.cjs.map +1 -0
- package/build/index.d.ts +4 -0
- package/build/index.js +5 -0
- package/build/index.js.map +1 -0
- package/build/option.cjs +279 -0
- package/build/option.cjs.map +1 -0
- package/build/option.d.ts +356 -0
- package/build/option.js +157 -0
- package/build/option.js.map +1 -0
- package/build/result.cjs +381 -0
- package/build/result.cjs.map +1 -0
- package/build/result.d.ts +442 -0
- package/build/result.js +229 -0
- package/build/result.js.map +1 -0
- package/build/safe.cjs +88 -0
- package/build/safe.cjs.map +1 -0
- package/build/safe.d.ts +29 -0
- package/build/safe.js +18 -0
- package/build/safe.js.map +1 -0
- package/build/testing.cjs +111 -0
- package/build/testing.cjs.map +1 -0
- package/build/testing.d.ts +85 -0
- package/build/testing.js +81 -0
- package/build/testing.js.map +1 -0
- package/build/types.cjs +78 -0
- package/build/types.cjs.map +1 -0
- package/build/types.d.ts +137 -0
- package/build/types.js +36 -0
- package/build/types.js.map +1 -0
- package/build/unsafe.cjs +82 -0
- package/build/unsafe.cjs.map +1 -0
- package/build/unsafe.d.ts +27 -0
- package/build/unsafe.js +11 -0
- package/build/unsafe.js.map +1 -0
- package/package.json +93 -0
- package/src/__tests__/index.ts +13 -0
- package/src/__tests__/option.ts +610 -0
- package/src/__tests__/option.types.ts +120 -0
- package/src/__tests__/result.ts +721 -0
- package/src/__tests__/result.types.ts +249 -0
- package/src/__tests__/safe.ts +24 -0
- package/src/__tests__/tooling.ts +86 -0
- package/src/__tests__/unsafe.ts +24 -0
- package/src/devtools.ts +97 -0
- package/src/index.ts +18 -0
- package/src/option.ts +510 -0
- package/src/result.ts +676 -0
- package/src/safe.ts +58 -0
- package/src/testing.ts +159 -0
- package/src/types.ts +201 -0
- package/src/unsafe.ts +47 -0
package/src/result.ts
ADDED
|
@@ -0,0 +1,676 @@
|
|
|
1
|
+
import { err as ERR, isOk, isErr, isSome, isNone, NONE, optionOf } from './types.js';
|
|
2
|
+
import type { Ok, Err, Result, Option, Widen, WidenNever } from './types.js';
|
|
3
|
+
|
|
4
|
+
export type { Ok, Err, Result };
|
|
5
|
+
export { isOk, isErr };
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Executes a function and captures the result or error.
|
|
9
|
+
* @param fn - Function to execute
|
|
10
|
+
* @param onError - Optional error transformer
|
|
11
|
+
* @returns Ok(result) if successful, Err(error) if thrown
|
|
12
|
+
* @example
|
|
13
|
+
* tryCatch(() => JSON.parse('{"a":1}')) // Ok({a: 1})
|
|
14
|
+
* tryCatch(() => JSON.parse('invalid')) // Err(SyntaxError)
|
|
15
|
+
* tryCatch(() => { throw 'oops' }, e => e) // Err('oops')
|
|
16
|
+
*/
|
|
17
|
+
export function tryCatch<T, E = unknown>(fn: () => T, onError?: (error: unknown) => E): Result<T, E> {
|
|
18
|
+
try {
|
|
19
|
+
return fn() as Ok<T>;
|
|
20
|
+
} catch (error) {
|
|
21
|
+
return ERR(onError ? onError(error) : (error as E));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Alias for tryCatch. Executes a function and captures the result or error.
|
|
27
|
+
* @param fn - Function to execute
|
|
28
|
+
* @returns Ok(result) if successful, Err(error) if thrown
|
|
29
|
+
*/
|
|
30
|
+
export function of<T, E = unknown>(fn: () => T): Result<T, E> {
|
|
31
|
+
return tryCatch(fn);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Executes an async function and captures the result or error.
|
|
36
|
+
* @param fn - Async function to execute
|
|
37
|
+
* @param onError - Optional error transformer
|
|
38
|
+
* @returns Promise of Ok(result) if successful, Err(error) if rejected
|
|
39
|
+
* @example
|
|
40
|
+
* await tryAsync(() => fetch('/api').then(r => r.json())) // Ok(data) or Err(error)
|
|
41
|
+
*/
|
|
42
|
+
export async function tryAsync<T, E = unknown>(fn: () => Promise<T>, onError?: (error: unknown) => E): Promise<Result<T, E>> {
|
|
43
|
+
try {
|
|
44
|
+
return (await fn()) as Ok<T>;
|
|
45
|
+
} catch (error) {
|
|
46
|
+
return ERR(onError ? onError(error) : (error as E));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Alias for tryAsync. Executes an async function and captures the result or error.
|
|
52
|
+
* @param fn - Async function to execute
|
|
53
|
+
* @returns Promise of Ok(result) if successful, Err(error) if rejected
|
|
54
|
+
*/
|
|
55
|
+
export function ofAsync<T, E = unknown>(fn: () => Promise<T>): Promise<Result<T, E>> {
|
|
56
|
+
return tryAsync(fn);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Converts a Promise to a Result.
|
|
61
|
+
* @param promise - The promise to convert
|
|
62
|
+
* @param onRejected - Optional rejection handler
|
|
63
|
+
* @returns Promise of Ok(value) if resolved, Err(error) if rejected
|
|
64
|
+
* @example
|
|
65
|
+
* await fromPromise(Promise.resolve(42)) // Ok(42)
|
|
66
|
+
* await fromPromise(Promise.reject('error')) // Err('error')
|
|
67
|
+
*/
|
|
68
|
+
export async function fromPromise<T, E = unknown>(promise: Promise<T>, onRejected?: (reason: unknown) => E): Promise<Result<T, E>> {
|
|
69
|
+
try {
|
|
70
|
+
return (await promise) as Ok<T>;
|
|
71
|
+
} catch (error) {
|
|
72
|
+
return ERR(onRejected ? onRejected(error) : (error as E));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Unwraps an Ok value or returns a computed value for Err.
|
|
78
|
+
* @param result - The Result to unwrap
|
|
79
|
+
* @param onErr - Function called with error if Err
|
|
80
|
+
* @returns The Ok value or result of onErr(error)
|
|
81
|
+
* @example
|
|
82
|
+
* unwrapOrReturn(ok(42), e => 0) // 42
|
|
83
|
+
* unwrapOrReturn(err('fail'), e => 0) // 0
|
|
84
|
+
*/
|
|
85
|
+
export function unwrapOrReturn<T, E, const R>(result: Result<T, E>, onErr: (error: E) => R): T | R {
|
|
86
|
+
return isOk(result) ? result : onErr(result.error);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Asserts that a Result is Ok, throwing if Err.
|
|
91
|
+
* @param result - The Result to assert
|
|
92
|
+
* @param message - Custom error message
|
|
93
|
+
* @throws Error if result is Err
|
|
94
|
+
* @example
|
|
95
|
+
* assertOk(ok(42)) // passes
|
|
96
|
+
* assertOk(err('failed')) // throws Error
|
|
97
|
+
*/
|
|
98
|
+
export function assertOk<T, E>(result: Result<T, E>, message?: string): asserts result is Ok<T> {
|
|
99
|
+
if (isErr(result)) {
|
|
100
|
+
throw new Error(message ?? `Expected Ok result. Received error: ${String((result as Err<E>).error)}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Asserts that a Result is Err, throwing if Ok.
|
|
106
|
+
* @param result - The Result to assert
|
|
107
|
+
* @param message - Custom error message
|
|
108
|
+
* @throws Error if result is Ok
|
|
109
|
+
* @example
|
|
110
|
+
* assertErr(err('failed')) // passes
|
|
111
|
+
* assertErr(ok(42)) // throws Error
|
|
112
|
+
*/
|
|
113
|
+
export function assertErr<T, E>(result: Result<T, E>, message?: string): asserts result is Err<E> {
|
|
114
|
+
if (isOk(result)) {
|
|
115
|
+
throw new Error(message ?? 'Expected Err result.');
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Checks if result is Err with a non-null error value.
|
|
121
|
+
* @param result - The Result to check
|
|
122
|
+
* @returns true if Err with Some error value
|
|
123
|
+
*/
|
|
124
|
+
export function isSomeErr<T, E>(result: Result<T, E>): boolean {
|
|
125
|
+
return isErr(result) && isSome((result as Err<E>).error);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Transforms the Ok value, leaving Err unchanged.
|
|
130
|
+
* @param result - The Result to map
|
|
131
|
+
* @param fn - Transform function
|
|
132
|
+
* @returns Ok(fn(value)) if Ok, Err unchanged
|
|
133
|
+
* @example
|
|
134
|
+
* map(ok(2), x => x * 2) // Ok(4)
|
|
135
|
+
* map(err('e'), x => x * 2) // Err('e')
|
|
136
|
+
*/
|
|
137
|
+
export function map<T, U, E>(result: Err<E>, fn: (value: T) => U): Err<E>;
|
|
138
|
+
export function map<T, U>(result: Ok<T>, fn: (value: T) => U): Ok<U>;
|
|
139
|
+
export function map<T, U, E>(result: Result<T, E>, fn: (value: T) => U): Result<U, E>;
|
|
140
|
+
export function map<T, U, E>(result: Result<T, E>, fn: (value: T) => U): Result<U, E> {
|
|
141
|
+
if (isErr(result)) return result as Err<E>;
|
|
142
|
+
return fn(result as Ok<T>) as Ok<U>;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Transforms the Err value, leaving Ok unchanged.
|
|
147
|
+
* @param result - The Result to map
|
|
148
|
+
* @param fn - Error transform function
|
|
149
|
+
* @returns Err(fn(error)) if Err, Ok unchanged
|
|
150
|
+
* @example
|
|
151
|
+
* mapErr(err('e'), e => e.toUpperCase()) // Err('E')
|
|
152
|
+
* mapErr(ok(42), e => e.toUpperCase()) // Ok(42)
|
|
153
|
+
*/
|
|
154
|
+
export function mapErr<T, E, F>(result: Ok<T>, fn: (error: E) => F): Ok<T>;
|
|
155
|
+
export function mapErr<E, F>(result: Err<E>, fn: (error: E) => F): Err<F>;
|
|
156
|
+
export function mapErr<T, E, F>(result: Result<T, E>, fn: (error: E) => F): Result<T, F>;
|
|
157
|
+
export function mapErr<T, E, F>(result: Result<T, E>, fn: (error: E) => F): Result<T, F> {
|
|
158
|
+
if (isOk(result)) return result;
|
|
159
|
+
return ERR(fn(result.error));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Chains Result-returning functions. Returns Err if the input is Err.
|
|
164
|
+
* @param result - The Result to chain
|
|
165
|
+
* @param fn - Function returning a Result
|
|
166
|
+
* @returns The result of fn(value) if Ok, Err unchanged
|
|
167
|
+
* @example
|
|
168
|
+
* flatMap(ok(2), x => ok(x * 2)) // Ok(4)
|
|
169
|
+
* flatMap(ok(2), x => err('fail')) // Err('fail')
|
|
170
|
+
* flatMap(err('e'), x => ok(x * 2)) // Err('e')
|
|
171
|
+
*/
|
|
172
|
+
export function flatMap<T, U, E>(result: Err<E>, fn: (value: T) => Result<U, E>): Err<E>;
|
|
173
|
+
export function flatMap<T, U, E>(result: Result<T, E>, fn: (value: T) => Result<U, E>): Result<U, E>;
|
|
174
|
+
export function flatMap<T, U, E>(result: Result<T, E>, fn: (value: T) => Result<U, E>): Result<U, E> {
|
|
175
|
+
if (isErr(result)) return result as Err<E>;
|
|
176
|
+
return fn(result as Ok<T>);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Alias for flatMap. Chains Result-returning functions.
|
|
181
|
+
* @param result - The Result to chain
|
|
182
|
+
* @param fn - Function returning a Result
|
|
183
|
+
* @returns The result of fn(value) if Ok, Err unchanged
|
|
184
|
+
*/
|
|
185
|
+
export function andThen<T, U, E>(result: Err<E>, fn: (value: T) => Result<U, E>): Err<E>;
|
|
186
|
+
export function andThen<T, U, E>(result: Result<T, E>, fn: (value: T) => Result<U, E>): Result<U, E>;
|
|
187
|
+
export function andThen<T, U, E>(result: Result<T, E>, fn: (value: T) => Result<U, E>): Result<U, E> {
|
|
188
|
+
return flatMap(result, fn);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Executes a side effect if Ok, then returns the original Result.
|
|
193
|
+
* @param result - The Result to tap
|
|
194
|
+
* @param fn - Side effect function
|
|
195
|
+
* @returns The original Result unchanged
|
|
196
|
+
* @example
|
|
197
|
+
* tap(ok(42), x => console.log(x)) // logs 42, returns Ok(42)
|
|
198
|
+
*/
|
|
199
|
+
export function tap<T, E>(result: Err<E>, fn: (value: T) => void): Err<E>;
|
|
200
|
+
export function tap<T>(result: Ok<T>, fn: (value: T) => void): Ok<T>;
|
|
201
|
+
export function tap<T, E>(result: Result<T, E>, fn: (value: T) => void): Result<T, E>;
|
|
202
|
+
export function tap<T, E>(result: Result<T, E>, fn: (value: T) => void): Result<T, E> {
|
|
203
|
+
if (isOk(result)) {
|
|
204
|
+
fn(result);
|
|
205
|
+
}
|
|
206
|
+
return result;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Executes a side effect if Err, then returns the original Result.
|
|
211
|
+
* @param result - The Result to tap
|
|
212
|
+
* @param fn - Side effect function for error
|
|
213
|
+
* @returns The original Result unchanged
|
|
214
|
+
* @example
|
|
215
|
+
* tapErr(err('fail'), e => console.log(e)) // logs 'fail', returns Err('fail')
|
|
216
|
+
*/
|
|
217
|
+
export function tapErr<T, E>(result: Ok<T>, fn: (error: E) => void): Ok<T>;
|
|
218
|
+
export function tapErr<E>(result: Err<E>, fn: (error: E) => void): Err<E>;
|
|
219
|
+
export function tapErr<T, E>(result: Result<T, E>, fn: (error: E) => void): Result<T, E>;
|
|
220
|
+
export function tapErr<T, E>(result: Result<T, E>, fn: (error: E) => void): Result<T, E> {
|
|
221
|
+
if (isErr(result)) {
|
|
222
|
+
fn((result as Err<E>).error);
|
|
223
|
+
}
|
|
224
|
+
return result;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Maps both Ok and Err values simultaneously.
|
|
229
|
+
* @param result - The Result to map
|
|
230
|
+
* @param okFn - Transform for Ok value
|
|
231
|
+
* @param errFn - Transform for Err value
|
|
232
|
+
* @returns Ok(okFn(value)) if Ok, Err(errFn(error)) if Err
|
|
233
|
+
* @example
|
|
234
|
+
* bimap(ok(2), x => x * 2, e => e.toUpperCase()) // Ok(4)
|
|
235
|
+
* bimap(err('e'), x => x * 2, e => e.toUpperCase()) // Err('E')
|
|
236
|
+
*/
|
|
237
|
+
export function bimap<T, U, E, F>(result: Ok<T>, okFn: (value: T) => U, errFn: (error: E) => F): Ok<U>;
|
|
238
|
+
export function bimap<T, U, E, F>(result: Err<E>, okFn: (value: T) => U, errFn: (error: E) => F): Err<F>;
|
|
239
|
+
export function bimap<T, U, E, F>(result: Result<T, E>, okFn: (value: T) => U, errFn: (error: E) => F): Result<U, F>;
|
|
240
|
+
export function bimap<T, U, E, F>(result: Result<T, E>, okFn: (value: T) => U, errFn: (error: E) => F): Result<U, F> {
|
|
241
|
+
return isOk(result) ? (okFn(result) as Ok<U>) : ERR(errFn(result.error));
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Extracts the Ok value, throws if Err.
|
|
246
|
+
* @param result - The Result to unwrap
|
|
247
|
+
* @returns The contained Ok value
|
|
248
|
+
* @throws Error if result is Err
|
|
249
|
+
* @example
|
|
250
|
+
* unwrap(ok(42)) // 42
|
|
251
|
+
* unwrap(err('failed')) // throws Error
|
|
252
|
+
*/
|
|
253
|
+
export function unwrap<T, E>(result: Result<T, E>): T {
|
|
254
|
+
if (isErr(result)) {
|
|
255
|
+
throw new Error(`Called unwrap on Err: ${String((result as Err<E>).error)}`);
|
|
256
|
+
}
|
|
257
|
+
return result as T;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Extracts the Err value, throws if Ok.
|
|
262
|
+
* @param result - The Result to unwrap
|
|
263
|
+
* @returns The contained error
|
|
264
|
+
* @throws Error if result is Ok
|
|
265
|
+
* @example
|
|
266
|
+
* unwrapErr(err('failed')) // 'failed'
|
|
267
|
+
* unwrapErr(ok(42)) // throws Error
|
|
268
|
+
*/
|
|
269
|
+
export function unwrapErr<T, E>(result: Result<T, E>): E {
|
|
270
|
+
if (isOk(result)) {
|
|
271
|
+
throw new Error(`Called unwrapErr on Ok: ${String(result)}`);
|
|
272
|
+
}
|
|
273
|
+
return result.error;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Extracts the Ok value, or returns a default.
|
|
278
|
+
* @param result - The Result to unwrap
|
|
279
|
+
* @param defaultValue - Value if Err
|
|
280
|
+
* @returns The Ok value or defaultValue
|
|
281
|
+
* @example
|
|
282
|
+
* unwrapOr(ok(42), 0) // 42
|
|
283
|
+
* unwrapOr(err('failed'), 0) // 0
|
|
284
|
+
*/
|
|
285
|
+
export function unwrapOr<T, E>(result: Result<T, E>, defaultValue: T): T {
|
|
286
|
+
return isOk(result) ? result : defaultValue;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Extracts the Ok value, or computes a default from the error.
|
|
291
|
+
* @param result - The Result to unwrap
|
|
292
|
+
* @param fn - Function to compute default from error
|
|
293
|
+
* @returns The Ok value or fn(error)
|
|
294
|
+
* @example
|
|
295
|
+
* unwrapOrElse(ok(42), e => 0) // 42
|
|
296
|
+
* unwrapOrElse(err('failed'), e => 0) // 0
|
|
297
|
+
*/
|
|
298
|
+
export function unwrapOrElse<T, E>(result: Result<T, E>, fn: (error: E) => T): T {
|
|
299
|
+
return isOk(result) ? result : fn(result.error);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Maps the Ok value and returns it, or returns a default.
|
|
304
|
+
* @param result - The Result to map
|
|
305
|
+
* @param defaultValue - Value if Err
|
|
306
|
+
* @param fn - Transform function
|
|
307
|
+
* @returns fn(value) if Ok, defaultValue otherwise
|
|
308
|
+
* @example
|
|
309
|
+
* mapOr(ok(2), 0, x => x * 2) // 4
|
|
310
|
+
* mapOr(err('e'), 0, x => x * 2) // 0
|
|
311
|
+
*/
|
|
312
|
+
export function mapOr<T, E, U>(result: Result<T, E>, defaultValue: U, fn: (value: T) => U): U {
|
|
313
|
+
return isOk(result) ? fn(result) : defaultValue;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Maps the Ok value and returns it, or computes a default.
|
|
318
|
+
* @param result - The Result to map
|
|
319
|
+
* @param defaultFn - Function to compute default
|
|
320
|
+
* @param fn - Transform function
|
|
321
|
+
* @returns fn(value) if Ok, defaultFn() otherwise
|
|
322
|
+
* @example
|
|
323
|
+
* mapOrElse(ok(2), () => 0, x => x * 2) // 4
|
|
324
|
+
* mapOrElse(err('e'), () => 0, x => x * 2) // 0
|
|
325
|
+
*/
|
|
326
|
+
export function mapOrElse<T, E, U>(result: Result<T, E>, defaultFn: () => U, fn: (value: T) => U): U {
|
|
327
|
+
return isOk(result) ? fn(result) : defaultFn();
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Extracts the Ok value, throws with custom message if Err.
|
|
332
|
+
* @param result - The Result to unwrap
|
|
333
|
+
* @param message - Error message prefix if Err
|
|
334
|
+
* @returns The Ok value
|
|
335
|
+
* @throws Error with message if Err
|
|
336
|
+
* @example
|
|
337
|
+
* expect(ok(42), 'missing value') // 42
|
|
338
|
+
* expect(err('fail'), 'missing value') // throws Error('missing value: fail')
|
|
339
|
+
*/
|
|
340
|
+
export function expect<T, E>(result: Result<T, E>, message: string): T {
|
|
341
|
+
if (isErr(result)) {
|
|
342
|
+
throw new Error(`${message}: ${String((result as Err<E>).error)}`);
|
|
343
|
+
}
|
|
344
|
+
return result as Ok<T>;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Extracts the Err value, throws with custom message if Ok.
|
|
349
|
+
* @param result - The Result to unwrap
|
|
350
|
+
* @param message - Error message prefix if Ok
|
|
351
|
+
* @returns The error value
|
|
352
|
+
* @throws Error with message if Ok
|
|
353
|
+
* @example
|
|
354
|
+
* expectErr(err('fail'), 'expected error') // 'fail'
|
|
355
|
+
* expectErr(ok(42), 'expected error') // throws Error
|
|
356
|
+
*/
|
|
357
|
+
export function expectErr<T, E>(result: Result<T, E>, message: string): E {
|
|
358
|
+
if (isOk(result)) {
|
|
359
|
+
throw new Error(`${message}: ${String(result)}`);
|
|
360
|
+
}
|
|
361
|
+
return result.error;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Returns other if result is Ok, otherwise returns the Err.
|
|
366
|
+
* @param result - First Result
|
|
367
|
+
* @param other - Second Result
|
|
368
|
+
* @returns other if result is Ok, result (Err) otherwise
|
|
369
|
+
* @example
|
|
370
|
+
* and(ok(1), ok(2)) // Ok(2)
|
|
371
|
+
* and(err('e'), ok(2)) // Err('e')
|
|
372
|
+
*/
|
|
373
|
+
export function and<T, U, E>(result: Result<T, E>, other: Result<U, E>): Result<U, E> {
|
|
374
|
+
return isOk(result) ? other : result;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Returns result if Ok, otherwise returns other.
|
|
379
|
+
* @param result - First Result
|
|
380
|
+
* @param other - Fallback Result
|
|
381
|
+
* @returns result if Ok, other otherwise
|
|
382
|
+
* @example
|
|
383
|
+
* or(ok(1), ok(2)) // Ok(1)
|
|
384
|
+
* or(err('e'), ok(2)) // Ok(2)
|
|
385
|
+
*/
|
|
386
|
+
export function or<T, E, F>(result: Result<T, E>, other: Result<T, F>): Result<T, F> {
|
|
387
|
+
return isOk(result) ? result : other;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Returns result if Ok, otherwise computes a fallback from the error.
|
|
392
|
+
* @param result - First Result
|
|
393
|
+
* @param fn - Function to compute fallback
|
|
394
|
+
* @returns result if Ok, fn(error) otherwise
|
|
395
|
+
* @example
|
|
396
|
+
* orElse(ok(1), e => ok(0)) // Ok(1)
|
|
397
|
+
* orElse(err('e'), e => ok(0)) // Ok(0)
|
|
398
|
+
*/
|
|
399
|
+
export function orElse<T, E, F>(result: Result<T, E>, fn: (error: E) => Result<T, F>): Result<T, F> {
|
|
400
|
+
return isOk(result) ? result : fn(result.error);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Converts a Result to an Option, discarding the error.
|
|
405
|
+
* @param result - The Result to convert
|
|
406
|
+
* @returns Some(value) if Ok, None if Err
|
|
407
|
+
* @example
|
|
408
|
+
* toOption(ok(42)) // Some(42)
|
|
409
|
+
* toOption(err('failed')) // None
|
|
410
|
+
*/
|
|
411
|
+
export function toOption<T, E>(result: Result<T, E>): Option<T> {
|
|
412
|
+
return isOk(result) ? optionOf(result) : NONE;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Converts a Result's error to an Option.
|
|
417
|
+
* @param result - The Result to convert
|
|
418
|
+
* @returns Some(error) if Err, None if Ok
|
|
419
|
+
* @example
|
|
420
|
+
* toErrorOption(err('failed')) // Some('failed')
|
|
421
|
+
* toErrorOption(ok(42)) // None
|
|
422
|
+
*/
|
|
423
|
+
export function toErrorOption<T, E>(result: Result<T, E>): Option<E> {
|
|
424
|
+
return isErr(result) ? optionOf((result as Err<E>).error) : NONE;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Combines two Results into a Result of a tuple.
|
|
429
|
+
* @param left - First Result
|
|
430
|
+
* @param right - Second Result
|
|
431
|
+
* @returns Ok([a, b]) if both Ok, first Err otherwise
|
|
432
|
+
* @example
|
|
433
|
+
* zip(ok(1), ok('a')) // Ok([1, 'a'])
|
|
434
|
+
* zip(ok(1), err('e')) // Err('e')
|
|
435
|
+
*/
|
|
436
|
+
export function zip<T, U, E>(left: Result<T, E>, right: Result<U, E>): Result<[T, U], E> {
|
|
437
|
+
if (isErr(left)) return left as Err<E>;
|
|
438
|
+
if (isErr(right)) return right as Err<E>;
|
|
439
|
+
return [left as Ok<T>, right as Ok<U>] as Ok<[T, U]>;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Combines two Results using a function.
|
|
444
|
+
* @param left - First Result
|
|
445
|
+
* @param right - Second Result
|
|
446
|
+
* @param fn - Combining function
|
|
447
|
+
* @returns Ok(fn(a, b)) if both Ok, first Err otherwise
|
|
448
|
+
* @example
|
|
449
|
+
* zipWith(ok(2), ok(3), (a, b) => a + b) // Ok(5)
|
|
450
|
+
*/
|
|
451
|
+
export function zipWith<T, U, V, E>(left: Result<T, E>, right: Result<U, E>, fn: (left: T, right: U) => V): Result<V, E> {
|
|
452
|
+
if (isErr(left)) return left as Err<E>;
|
|
453
|
+
if (isErr(right)) return right as Err<E>;
|
|
454
|
+
return fn(left as Ok<T>, right as Ok<U>) as Ok<V>;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Flattens a nested Result.
|
|
459
|
+
* @param result - Result containing a Result
|
|
460
|
+
* @returns The inner Result
|
|
461
|
+
* @example
|
|
462
|
+
* flatten(ok(ok(42))) // Ok(42)
|
|
463
|
+
* flatten(ok(err('e'))) // Err('e')
|
|
464
|
+
* flatten(err('outer')) // Err('outer')
|
|
465
|
+
*/
|
|
466
|
+
export function flatten<T, E>(result: Result<Result<T, E>, E>): Result<T, E> {
|
|
467
|
+
return isErr(result) ? (result as Err<E>) : (result as Result<T, E>);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Pattern matches on a Result, handling both Ok and Err cases.
|
|
472
|
+
* @param result - The Result to match
|
|
473
|
+
* @param onOk - Handler for Ok case
|
|
474
|
+
* @param onErr - Handler for Err case
|
|
475
|
+
* @returns Result of the matching handler
|
|
476
|
+
* @example
|
|
477
|
+
* match(ok(42), x => x * 2, e => 0) // 84
|
|
478
|
+
* match(err('e'), x => x * 2, e => 0) // 0
|
|
479
|
+
*/
|
|
480
|
+
export function match<T, E, U>(result: Result<T, E>, onOk: (value: T) => U, onErr: (error: E) => U): U {
|
|
481
|
+
return isOk(result) ? onOk(result) : onErr(result.error);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Separates an array of Results into Ok values and Err values.
|
|
486
|
+
* @param results - Array of Results
|
|
487
|
+
* @returns Tuple of [Ok values, Err values]
|
|
488
|
+
* @example
|
|
489
|
+
* partition([ok(1), err('a'), ok(2)]) // [[1, 2], ['a']]
|
|
490
|
+
*/
|
|
491
|
+
export function partition<T, E>(results: Result<T, E>[]): [T[], E[]] {
|
|
492
|
+
const oks: T[] = [];
|
|
493
|
+
const errs: E[] = [];
|
|
494
|
+
|
|
495
|
+
for (const result of results) {
|
|
496
|
+
if (isOk(result)) {
|
|
497
|
+
oks.push(result);
|
|
498
|
+
} else {
|
|
499
|
+
errs.push(result.error);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
return [oks, errs];
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* Collects an array of Results into a Result of an array. Fails on first Err.
|
|
508
|
+
* @param results - Array of Results
|
|
509
|
+
* @returns Ok(values) if all Ok, first Err otherwise
|
|
510
|
+
* @example
|
|
511
|
+
* collect([ok(1), ok(2)]) // Ok([1, 2])
|
|
512
|
+
* collect([ok(1), err('e')]) // Err('e')
|
|
513
|
+
*/
|
|
514
|
+
export function collect<T, E>(results: Result<T, E>[]): Result<T[], E> {
|
|
515
|
+
const values: T[] = [];
|
|
516
|
+
|
|
517
|
+
for (const result of results) {
|
|
518
|
+
if (isErr(result)) {
|
|
519
|
+
return result as Err<E>;
|
|
520
|
+
}
|
|
521
|
+
values.push(result as Ok<T>);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
return values as Ok<T[]>;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* Collects all Results, returning all errors if any exist.
|
|
529
|
+
* @param results - Array of Results
|
|
530
|
+
* @returns Ok(values) if all Ok, Err(allErrors) otherwise
|
|
531
|
+
* @example
|
|
532
|
+
* collectAll([ok(1), ok(2)]) // Ok([1, 2])
|
|
533
|
+
* collectAll([ok(1), err('a'), err('b')]) // Err(['a', 'b'])
|
|
534
|
+
*/
|
|
535
|
+
export function collectAll<T, E>(results: Result<T, E>[]): Result<T[], E[]> {
|
|
536
|
+
const [oks, errs] = partition(results);
|
|
537
|
+
return errs.length > 0 ? ERR(errs) : (oks as Ok<T[]>);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/**
|
|
541
|
+
* Alias for collect with widened types. Collects Results into a Result of array.
|
|
542
|
+
* @param results - Array of Results
|
|
543
|
+
* @returns Ok(values) if all Ok, first Err otherwise
|
|
544
|
+
*/
|
|
545
|
+
export function all<T, E>(results: Result<T, E>[]): Result<Widen<T>[], WidenNever<E>> {
|
|
546
|
+
return collect(results) as Result<Widen<T>[], WidenNever<E>>;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* Returns the first Ok, or all errors if none succeed.
|
|
551
|
+
* @param results - Array of Results
|
|
552
|
+
* @returns First Ok found, or Err(allErrors) if all fail
|
|
553
|
+
* @example
|
|
554
|
+
* any([err('a'), ok(1), err('b')]) // Ok(1)
|
|
555
|
+
* any([err('a'), err('b')]) // Err(['a', 'b'])
|
|
556
|
+
*/
|
|
557
|
+
export function any<T, E>(results: Result<T, E>[]): Result<Widen<T>, WidenNever<E>[]> {
|
|
558
|
+
const len = results.length;
|
|
559
|
+
const errors = new Array<WidenNever<E>>(len);
|
|
560
|
+
for (let i = 0; i < len; i++) {
|
|
561
|
+
const result = results[i];
|
|
562
|
+
if (isOk(result)) return result as Ok<Widen<T>>;
|
|
563
|
+
errors[i] = (result as Err<WidenNever<E>>).error;
|
|
564
|
+
}
|
|
565
|
+
return ERR(errors);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* Transposes a Result of Option to an Option of Result.
|
|
570
|
+
* @param result - Result containing an Option
|
|
571
|
+
* @returns Some(Ok(value)) if Ok(Some), None if Ok(None), Some(Err) if Err
|
|
572
|
+
* @example
|
|
573
|
+
* transpose(ok(some(42))) // Some(Ok(42))
|
|
574
|
+
* transpose(ok(none)) // None
|
|
575
|
+
* transpose(err('e')) // Some(Err('e'))
|
|
576
|
+
*/
|
|
577
|
+
export function transpose<T, E>(result: Result<Option<T>, E>): Option<Result<T, E>> {
|
|
578
|
+
if (isErr(result)) {
|
|
579
|
+
return ERR((result as Err<E>).error) as Option<Result<T, E>>;
|
|
580
|
+
}
|
|
581
|
+
const opt = result as Option<T>;
|
|
582
|
+
return isNone(opt) ? NONE : (opt as unknown as Ok<T> as Option<Result<T, E>>);
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Checks if Ok and the value satisfies a predicate.
|
|
587
|
+
* @param result - The Result to check
|
|
588
|
+
* @param predicate - Test function
|
|
589
|
+
* @returns true if Ok and predicate returns true
|
|
590
|
+
* @example
|
|
591
|
+
* isOkAnd(ok(4), x => x > 2) // true
|
|
592
|
+
* isOkAnd(ok(1), x => x > 2) // false
|
|
593
|
+
* isOkAnd(err('e'), x => x > 2) // false
|
|
594
|
+
*/
|
|
595
|
+
export function isOkAnd<T, E>(result: Result<T, E>, predicate: (value: T) => boolean): boolean {
|
|
596
|
+
return isOk(result) && predicate(result);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
/**
|
|
600
|
+
* Checks if Err and the error satisfies a predicate.
|
|
601
|
+
* @param result - The Result to check
|
|
602
|
+
* @param predicate - Test function
|
|
603
|
+
* @returns true if Err and predicate returns true
|
|
604
|
+
* @example
|
|
605
|
+
* isErrAnd(err('fatal'), e => e.includes('fatal')) // true
|
|
606
|
+
* isErrAnd(ok(42), e => true) // false
|
|
607
|
+
*/
|
|
608
|
+
export function isErrAnd<T, E>(result: Result<T, E>, predicate: (error: E) => boolean): boolean {
|
|
609
|
+
return isErr(result) && predicate((result as Err<E>).error);
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* Maps an async function over an Ok value.
|
|
614
|
+
* @param result - The Result to map
|
|
615
|
+
* @param fn - Async transform function
|
|
616
|
+
* @param onRejected - Optional rejection handler
|
|
617
|
+
* @returns Promise of mapped Result
|
|
618
|
+
* @example
|
|
619
|
+
* await mapAsync(ok(2), async x => x * 2) // Ok(4)
|
|
620
|
+
*/
|
|
621
|
+
export async function mapAsync<T, U, E = unknown>(
|
|
622
|
+
result: Result<T, E>,
|
|
623
|
+
fn: (value: T) => Promise<U>,
|
|
624
|
+
onRejected?: (error: unknown) => E,
|
|
625
|
+
): Promise<Result<U, E>> {
|
|
626
|
+
if (isErr(result)) return result as Err<E>;
|
|
627
|
+
return fromPromise(fn(result as Ok<T>), onRejected);
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
/**
|
|
631
|
+
* Chains an async Result-returning function.
|
|
632
|
+
* @param result - The Result to chain
|
|
633
|
+
* @param fn - Async function returning a Result
|
|
634
|
+
* @returns Promise of the chained Result
|
|
635
|
+
* @example
|
|
636
|
+
* await andThenAsync(ok(2), async x => ok(x * 2)) // Ok(4)
|
|
637
|
+
*/
|
|
638
|
+
export async function andThenAsync<T, U, E>(result: Result<T, E>, fn: (value: T) => Promise<Result<U, E>>): Promise<Result<U, E>> {
|
|
639
|
+
if (isErr(result)) return result as Err<E>;
|
|
640
|
+
return fn(result as Ok<T>);
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
/**
|
|
644
|
+
* Pattern matches with async handlers.
|
|
645
|
+
* @param result - The Result to match
|
|
646
|
+
* @param onOk - Async handler for Ok
|
|
647
|
+
* @param onErr - Async handler for Err
|
|
648
|
+
* @returns Promise of the handler result
|
|
649
|
+
*/
|
|
650
|
+
export async function matchAsync<T, E, U>(result: Result<T, E>, onOk: (value: T) => Promise<U>, onErr: (error: E) => Promise<U>): Promise<U> {
|
|
651
|
+
return isOk(result) ? onOk(result) : onErr(result.error);
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
/**
|
|
655
|
+
* Partitions an async iterable of Results.
|
|
656
|
+
* @param results - Iterable of Promise Results
|
|
657
|
+
* @returns Promise of [Ok values, Err values]
|
|
658
|
+
* @example
|
|
659
|
+
* await partitionAsync([Promise.resolve(ok(1)), Promise.resolve(err('a'))])
|
|
660
|
+
* // [[1], ['a']]
|
|
661
|
+
*/
|
|
662
|
+
export async function partitionAsync<T, E>(results: Iterable<Promise<Result<T, E>>>): Promise<[Widen<T>[], WidenNever<E>[]]> {
|
|
663
|
+
const oks: Widen<T>[] = [];
|
|
664
|
+
const errs: WidenNever<E>[] = [];
|
|
665
|
+
|
|
666
|
+
for (const promise of results) {
|
|
667
|
+
const result = await promise;
|
|
668
|
+
if (isOk(result)) {
|
|
669
|
+
oks.push(result as Ok<Widen<T>>);
|
|
670
|
+
} else {
|
|
671
|
+
errs.push((result as Err<WidenNever<E>>).error);
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
return [oks, errs];
|
|
676
|
+
}
|