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.
Files changed (58) hide show
  1. package/README.md +282 -0
  2. package/build/devtools.cjs +79 -0
  3. package/build/devtools.cjs.map +1 -0
  4. package/build/devtools.d.ts +82 -0
  5. package/build/devtools.js +43 -0
  6. package/build/devtools.js.map +1 -0
  7. package/build/index.cjs +76 -0
  8. package/build/index.cjs.map +1 -0
  9. package/build/index.d.ts +4 -0
  10. package/build/index.js +5 -0
  11. package/build/index.js.map +1 -0
  12. package/build/option.cjs +279 -0
  13. package/build/option.cjs.map +1 -0
  14. package/build/option.d.ts +356 -0
  15. package/build/option.js +157 -0
  16. package/build/option.js.map +1 -0
  17. package/build/result.cjs +381 -0
  18. package/build/result.cjs.map +1 -0
  19. package/build/result.d.ts +442 -0
  20. package/build/result.js +229 -0
  21. package/build/result.js.map +1 -0
  22. package/build/safe.cjs +88 -0
  23. package/build/safe.cjs.map +1 -0
  24. package/build/safe.d.ts +29 -0
  25. package/build/safe.js +18 -0
  26. package/build/safe.js.map +1 -0
  27. package/build/testing.cjs +111 -0
  28. package/build/testing.cjs.map +1 -0
  29. package/build/testing.d.ts +85 -0
  30. package/build/testing.js +81 -0
  31. package/build/testing.js.map +1 -0
  32. package/build/types.cjs +78 -0
  33. package/build/types.cjs.map +1 -0
  34. package/build/types.d.ts +137 -0
  35. package/build/types.js +36 -0
  36. package/build/types.js.map +1 -0
  37. package/build/unsafe.cjs +82 -0
  38. package/build/unsafe.cjs.map +1 -0
  39. package/build/unsafe.d.ts +27 -0
  40. package/build/unsafe.js +11 -0
  41. package/build/unsafe.js.map +1 -0
  42. package/package.json +93 -0
  43. package/src/__tests__/index.ts +13 -0
  44. package/src/__tests__/option.ts +610 -0
  45. package/src/__tests__/option.types.ts +120 -0
  46. package/src/__tests__/result.ts +721 -0
  47. package/src/__tests__/result.types.ts +249 -0
  48. package/src/__tests__/safe.ts +24 -0
  49. package/src/__tests__/tooling.ts +86 -0
  50. package/src/__tests__/unsafe.ts +24 -0
  51. package/src/devtools.ts +97 -0
  52. package/src/index.ts +18 -0
  53. package/src/option.ts +510 -0
  54. package/src/result.ts +676 -0
  55. package/src/safe.ts +58 -0
  56. package/src/testing.ts +159 -0
  57. package/src/types.ts +201 -0
  58. 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
+ }