@@ -759,6 +759,287 @@ export interface IResult<T, E> {
759759 * });
760760 */
761761 tapFailThru ( fn : ( val : E ) => void ) : IResult < T , E >
762+
763+ /**
764+ * Transforms a Fail Result into an Ok Result using a recovery function.
765+ *
766+ * This method provides error handling by:
767+ * - If this Result is a Fail variant, it applies the function to the error to generate a recovery value
768+ * and returns a new Ok Result with that value
769+ * - If this Result is an Ok variant, it returns the original Result unchanged
770+ *
771+ * This is similar to a catch block in try/catch, but in a functional style.
772+ *
773+ * @param fn - A function that transforms the Fail value into a recovery value
774+ * @returns An Ok Result with either the original value or the recovered value
775+ *
776+ * @example
777+ * // Providing default values
778+ * const userResult = getUserById(userId)
779+ * .recover(error => ({
780+ * id: 0,
781+ * name: "Guest User",
782+ * isGuest: true
783+ * }));
784+ *
785+ * // userResult is guaranteed to be Ok
786+ * const user = userResult.unwrap(); // Safe, will never throw
787+ *
788+ * // Error logging with recovery
789+ * fetchData()
790+ * .tapFail(error => logError(error))
791+ * .recover(error => {
792+ * const fallbackData = getLocalData();
793+ * trackRecovery("data_fetch", error);
794+ * return fallbackData;
795+ * })
796+ * .map(data => processData(data)); // This will always run with either fetched or fallback data
797+ */
798+ recover ( fn : ( err : E ) => T ) : IResult < T , E >
799+
800+ /**
801+ * Transforms a Fail Result by applying a function that returns another Result.
802+ *
803+ * This method provides advanced error recovery by:
804+ * - If this Result is a Fail variant, it applies the function to the error, which returns a new Result
805+ * - If this Result is an Ok variant, it returns the original Result unchanged
806+ *
807+ * This is useful for fallback operations that might themselves fail.
808+ *
809+ * @param fn - A function that takes the Fail value and returns a new Result
810+ * @returns The original Result if Ok, or the Result returned by the function if Fail
811+ *
812+ * @example
813+ * // Trying a fallback operation that might also fail
814+ * fetchFromPrimaryAPI()
815+ * .recoverWith(error => {
816+ * logFailure(error, "primary_api");
817+ * // Try the backup API, which might also fail
818+ * return fetchFromBackupAPI();
819+ * })
820+ * .match({
821+ * ok: data => renderData(data),
822+ * fail: error => showFatalError("All data sources failed")
823+ * });
824+ *
825+ * // Authentication with multiple strategies
826+ * authenticateWithPassword(credentials)
827+ * .recoverWith(error => {
828+ * if (error.code === "CREDENTIALS_EXPIRED") {
829+ * return authenticateWithToken(refreshToken);
830+ * }
831+ * return fail(error); // Pass through other errors
832+ * })
833+ * .recoverWith(error => {
834+ * if (error.code === "TOKEN_EXPIRED") {
835+ * return authenticateWithOAuth();
836+ * }
837+ * return fail(error); // Pass through other errors
838+ * });
839+ */
840+ recoverWith ( fn : ( err : E ) => IResult < T , E > ) : IResult < T , E >
841+
842+ /**
843+ * Returns this Result if it's Ok, otherwise returns the provided fallback Result.
844+ *
845+ * This method allows for specifying an alternative Result:
846+ * - If this Result is an Ok variant, it is returned unchanged
847+ * - If this Result is a Fail variant, the fallback Result is returned
848+ *
849+ * @param fallback - The Result to return if this Result is Fail
850+ * @returns This Result if Ok, or the fallback Result if Fail
851+ *
852+ * @example
853+ * // Try multiple data sources in order
854+ * const userData = getUserFromCache(userId)
855+ * .orElse(getUserFromDatabase(userId))
856+ * .orElse(getUserFromBackupService(userId));
857+ *
858+ * // Providing a default value as a Result
859+ * const config = loadConfig()
860+ * .orElse(ok(DEFAULT_CONFIG));
861+ *
862+ * // config is guaranteed to be Ok
863+ * const configValue = config.unwrap(); // Safe, will never throw
864+ */
865+ orElse ( fallback : IResult < T , E > ) : IResult < T , E >
866+
867+ /**
868+ * Swaps the Ok and Fail values, creating a new Result with inversed variants.
869+ *
870+ * This method transforms:
871+ * - An Ok Result into a Fail Result with the same value (now as an error)
872+ * - A Fail Result into an Ok Result with the same error (now as a value)
873+ *
874+ * This can be useful for inverting logic or for protocols where the error case
875+ * is actually the expected or desired outcome.
876+ *
877+ * @returns A new Result with the Ok and Fail variants swapped
878+ *
879+ * @example
880+ * // Inverting validation logic
881+ * const isInvalid = validateInput(input) // Returns Ok if valid, Fail if invalid
882+ * .swap() // Returns Fail if valid, Ok if invalid
883+ * .isOk(); // true if the input was invalid
884+ *
885+ * // Working with negative conditions
886+ * const userNotFound = findUser(userId)
887+ * .swap()
888+ * .isOk(); // true if the user was not found
889+ *
890+ * // Converting between error domains
891+ * checkPermission(user, resource) // Returns Ok(true) if permitted, Fail(error) if not
892+ * .swap() // Returns Fail(true) if permitted, Ok(error) if not
893+ * .map(error => ({ // Only runs for permission errors
894+ * type: 'ACCESS_DENIED',
895+ * message: `Access denied: ${error.message}`,
896+ * resource
897+ * }))
898+ * .swap(); // Back to Ok for permitted, Fail for denied
899+ */
900+ swap ( ) : IResult < E , T >
901+
902+ /**
903+ * Combines this Result with another Result using a combining function.
904+ *
905+ * This method allows for working with two independent Results together:
906+ * - If both Results are Ok, applies the function to both values and returns an Ok Result
907+ * - If either Result is Fail, returns the first Fail Result encountered
908+ *
909+ * This is useful for combining data that comes from different sources where both
910+ * are needed to proceed.
911+ *
912+ * @param other - Another Result to combine with this one
913+ * @param fn - A function that combines the two Ok values
914+ * @returns A new Result containing either the combined values or the first error
915+ *
916+ * @example
917+ * // Combining user data and preferences that are loaded separately
918+ * const userData = fetchUserData(userId);
919+ * const userPrefs = fetchUserPreferences(userId);
920+ *
921+ * const userProfile = userData.zipWith(
922+ * userPrefs,
923+ * (data, prefs) => ({
924+ * ...data,
925+ * preferences: prefs,
926+ * theme: prefs.theme || 'default'
927+ * })
928+ * );
929+ *
930+ * // Working with multiple API responses
931+ * const orders = fetchOrders(userId);
932+ * const payments = fetchPayments(userId);
933+ *
934+ * const combinedData = orders.zipWith(
935+ * payments,
936+ * (orderList, paymentList) => {
937+ * return orderList.map(order => ({
938+ * ...order,
939+ * payments: paymentList.filter(p => p.orderId === order.id)
940+ * }));
941+ * }
942+ * );
943+ */
944+ zipWith < U , R > ( other : IResult < U , E > , fn : ( a : T , b : U ) => R ) : IResult < R , E >
945+
946+ /**
947+ * Maps the Ok value of this Result to a Promise, and then flattens the resulting structure.
948+ *
949+ * This method allows for seamless integration with asynchronous code:
950+ * - If this Result is an Ok variant, it applies the function to the contained value,
951+ * awaits the Promise, and wraps the resolved value in a new Ok Result
952+ * - If the Promise rejects, it returns a Fail Result with the rejection reason
953+ * - If this Result is a Fail variant, it returns a Promise that resolves to the
954+ * original Fail Result without calling the function
955+ *
956+ * @param fn - A function that takes the Ok value and returns a Promise
957+ * @returns A Promise that resolves to a new Result
958+ *
959+ * @example
960+ * // Chaining synchronous and asynchronous operations
961+ * validateUser(userData)
962+ * .flatMapPromise(user => saveUserToDatabase(user))
963+ * .then(result => result.match({
964+ * ok: savedUser => sendWelcomeEmail(savedUser),
965+ * fail: error => logError("Failed to save user", error)
966+ * }));
967+ *
968+ * // Multi-step asynchronous workflow
969+ * async function processOrder(orderData) {
970+ * // Start with sync validation returning a Result
971+ * const result = await validateOrder(orderData)
972+ * .flatMapPromise(async order => {
973+ * // Async payment processing
974+ * const paymentResult = await processPayment(order.paymentDetails);
975+ * if (!paymentResult.success) {
976+ * throw new Error(`Payment failed: ${paymentResult.message}`);
977+ * }
978+ *
979+ * // Async inventory check and allocation
980+ * await allocateInventory(order.items);
981+ *
982+ * // Return the processed order
983+ * return {
984+ * ...order,
985+ * status: 'PAID',
986+ * paymentId: paymentResult.id
987+ * };
988+ * })
989+ * .flatMapPromise(async paidOrder => {
990+ * // Final database save
991+ * const orderId = await saveOrderToDatabase(paidOrder);
992+ * return { ...paidOrder, id: orderId };
993+ * });
994+ *
995+ * return result;
996+ * }
997+ */
998+ flatMapPromise < M > ( fn : ( val : T ) => Promise < M > ) : Promise < IResult < M , E > >
999+
1000+ /**
1001+ * Maps the Ok value of this Result to an Observable, and then flattens the resulting structure.
1002+ *
1003+ * This method allows for seamless integration with reactive code:
1004+ * - If this Result is an Ok variant, it applies the function to the contained value,
1005+ * subscribes to the Observable, and wraps the first emitted value in a new Ok Result
1006+ * - If the Observable errors, it returns a Fail Result with the error
1007+ * - If the Observable completes without emitting, it returns a Fail Result with the provided default error
1008+ * - If this Result is a Fail variant, it returns a Promise that resolves to the
1009+ * original Fail Result without calling the function
1010+ *
1011+ * @param fn - A function that takes the Ok value and returns an Observable
1012+ * @param defaultError - The error to use if the Observable completes without emitting
1013+ * @returns A Promise that resolves to a new Result
1014+ *
1015+ * @requires rxjs@^7.0
1016+ * @example
1017+ * // Chaining Result with reactive code
1018+ * validateUser(userData)
1019+ * .flatMapObservable(
1020+ * user => userService.save(user),
1021+ * new Error("Failed to save user")
1022+ * )
1023+ * .then(result => result.match({
1024+ * ok: savedUser => notifyUserCreated(savedUser),
1025+ * fail: error => logError("User creation failed", error)
1026+ * }));
1027+ *
1028+ * // Processing real-time data
1029+ * getSensorData()
1030+ * .flatMapObservable(
1031+ * config => sensorApi.connectAndGetReading(config),
1032+ * new Error("No sensor reading received")
1033+ * )
1034+ * .then(result => result.match({
1035+ * ok: reading => updateDashboard(reading),
1036+ * fail: error => showSensorError(error)
1037+ * }));
1038+ */
1039+ flatMapObservable < M > (
1040+ fn : ( val : T ) => import ( 'rxjs' ) . Observable < M > ,
1041+ defaultError : E
1042+ ) : Promise < IResult < M , E > >
7621043}
7631044
7641045export interface IResultOk < T , E = never > extends IResult < T , E > {
0 commit comments