@@ -435,4 +435,124 @@ export interface IMaybe<T> extends IMonad<T> {
435
435
* // Converts a Maybe<User> to a Result<User, Error>
436
436
*/
437
437
toResult < E > ( error : E ) : IResult < T , E >
438
+
439
+ /**
440
+ * Chains Maybe operations with a function that returns a Promise.
441
+ *
442
+ * This allows for seamless integration with asynchronous operations.
443
+ * The Promise result is automatically wrapped in a Maybe, with null/undefined
444
+ * or rejected promises resulting in None.
445
+ *
446
+ * Note on resolution preservation: This method preserves both the Maybe context and
447
+ * the asynchronous nature of Promises:
448
+ * - None values short-circuit (the Promise-returning function is never called)
449
+ * - Some values are passed to the function, and its Promise result is processed
450
+ * - Promise rejections become None values in the resulting Maybe
451
+ * - Promise resolutions become Some values if non-nullish, None otherwise
452
+ *
453
+ * This approach preserves the monadic semantics while adding asynchronicity.
454
+ *
455
+ * @typeParam R - The type of the value in the resulting Promise
456
+ * @param fn - A function that takes the value from this Maybe and returns a Promise
457
+ * @returns A Promise that resolves to a Maybe containing the resolved value
458
+ *
459
+ * @example
460
+ * maybe(userId)
461
+ * .flatMapPromise(id => api.fetchUserProfile(id))
462
+ * .then(profileMaybe => profileMaybe.match({
463
+ * some: profile => displayProfile(profile),
464
+ * none: () => showProfileNotFound()
465
+ * }));
466
+ *
467
+ * // Chain multiple promises
468
+ * maybe(user)
469
+ * .flatMapPromise(user => fetchPermissions(user.id))
470
+ * .then(permissionsMaybe => permissionsMaybe.flatMap(permissions =>
471
+ * maybe(user).map(user => ({ ...user, permissions }))
472
+ * ))
473
+ * .then(userWithPermissions => renderUserDashboard(userWithPermissions));
474
+ */
475
+ flatMapPromise < R > ( fn : ( val : NonNullable < T > ) => Promise < R > ) : Promise < IMaybe < NonNullable < R > > >
476
+
477
+ /**
478
+ * Chains Maybe operations with a function that returns an Observable.
479
+ *
480
+ * This allows for seamless integration with reactive streams.
481
+ * The Observable result is automatically wrapped in a Maybe, with null/undefined
482
+ * or empty/error emissions resulting in None.
483
+ *
484
+ * Note on resolution transformation: This method transforms between context types while
485
+ * preserving semantic meaning:
486
+ * - None values short-circuit (the Observable-returning function is never called)
487
+ * - Some values are passed to the function to generate an Observable
488
+ * - Only the first emission from the Observable is captured (timing loss)
489
+ * - Observable emissions become Some values in the resulting Maybe
490
+ * - Observable completion without emissions or errors becomes None
491
+ * - Observable errors become None values
492
+ *
493
+ * There is timing model transformation: from continuous reactive to one-time asynchronous.
494
+ *
495
+ * @typeParam R - The type of the value emitted by the resulting Observable
496
+ * @param fn - A function that takes the value from this Maybe and returns an Observable
497
+ * @returns A Promise that resolves to a Maybe containing the first emitted value
498
+ *
499
+ * @requires rxjs@^7.0
500
+ * @example
501
+ * maybe(userId)
502
+ * .flatMapObservable(id => userService.getUserSettings(id))
503
+ * .then(settingsMaybe => settingsMaybe.match({
504
+ * some: settings => applyUserSettings(settings),
505
+ * none: () => applyDefaultSettings()
506
+ * }));
507
+ */
508
+ flatMapObservable < R > ( fn : ( val : NonNullable < T > ) => import ( 'rxjs' ) . Observable < R > ) : Promise < IMaybe < NonNullable < R > > >
509
+
510
+ /**
511
+ * Maps and flattens multiple Promises in parallel, preserving the Maybe context.
512
+ *
513
+ * This operation allows processing an array of async operations concurrently
514
+ * while maintaining the Maybe context. If the original Maybe is None, the
515
+ * function is never called. Otherwise, all Promises are executed in parallel.
516
+ *
517
+ * @typeParam R - The type returned by each Promise in the results array
518
+ * @param fn - A function that takes the value from this Maybe and returns an array of Promises
519
+ * @returns A Promise that resolves to a Maybe containing an array of results
520
+ *
521
+ * @example
522
+ * // Load multiple resources concurrently from a user ID
523
+ * maybe(userId)
524
+ * .flatMapMany(id => [
525
+ * api.fetchProfile(id),
526
+ * api.fetchPermissions(id),
527
+ * api.fetchSettings(id)
528
+ * ])
529
+ * .then(resultsMaybe => resultsMaybe.match({
530
+ * some: ([profile, permissions, settings]) => displayDashboard(profile, permissions, settings),
531
+ * none: () => showError('Failed to load user data')
532
+ * }));
533
+ */
534
+ flatMapMany < R > ( fn : ( val : NonNullable < T > ) => Promise < R > [ ] ) : Promise < IMaybe < NonNullable < R > [ ] > >
535
+
536
+ /**
537
+ * Combines this Maybe with another Maybe using a combiner function.
538
+ *
539
+ * If both Maybes are Some, applies the function to their values and returns
540
+ * a new Some containing the result. If either is None, returns None.
541
+ *
542
+ * @typeParam U - The type of the value in the other Maybe
543
+ * @typeParam R - The type of the combined result
544
+ * @param other - Another Maybe to combine with this one
545
+ * @param fn - A function that combines the values from both Maybes
546
+ * @returns A new Maybe containing the combined result if both inputs are Some, otherwise None
547
+ *
548
+ * @example
549
+ * // Combine user name and email into a display string
550
+ * const name = maybe(user.name);
551
+ * const email = maybe(user.email);
552
+ *
553
+ * const display = name.zipWith(email, (name, email) => `${name} <${email}>`);
554
+ * // Some("John Doe <[email protected] >") if both name and email exist
555
+ * // None if either is missing
556
+ */
557
+ zipWith < U extends NonNullable < unknown > , R > ( other : IMaybe < U > , fn : ( a : NonNullable < T > , b : U ) => NonNullable < R > ) : IMaybe < R >
438
558
}
0 commit comments