Skip to content

๐Ÿš€ Result Pattern v2.3.2 - Elevating Error Handling with valueOrError, match, and Chaining!

Latest
Compare
Choose a tag to compare
@caiolandgraf caiolandgraf released this 13 Mar 20:33
· 2 commits to main since this release

โœจ What's New in Result Pattern

This release introduces powerful new features that make working with the Result Pattern even more intuitive:

๐ŸŽ valueOrError() - Simplified Access to Values and Errors (Old unwrapOrGetErrors)

// Before: You had to handle Ok and Fail cases separately
if (result.isOk) {
  const value = result.value;
  // Use value
} else {
  const error = result.value;
  // Handle error
}

// Now: Get either the value or the error in one call!
const valueOrError = result.valueOrError();
// If result is Ok, valueOrError contains the success value
// If result is Fail, valueOrError contains the error value

This method is especially powerful when working with error handling:

const userId = getUserId(); // May be invalid
const result = getUser(userId);

// Get either the user or the error message directly
console.log(`Result: ${result.valueOrError()}`);
// If successful: "Result: {id: 123, name: 'Caio'}"
// If failed: "Result: Invalid user ID"

๐ŸŽฎ Elegant Pattern Matching with match

Another powerful feature is the match method, allowing elegant handling of both success and failure cases:

// Traditional approach with if/else
let message;
if (result.isOk) {
  message = `Welcome, ${result.value.name}!`;
} else {
  message = `Error: ${result.value}`;
}

// Now with pattern matching
const message = result.match({
  ok: user => `Welcome, ${user.name}!`,
  fail: error => `Error: ${error}`
});

๐Ÿ”„ Enhanced Flow Control with andThen and orElse

The andThen and orElse methods provide elegant ways to chain operations based on result status:

// andThen executes only if the result is Ok
const result = validateUser(user)
  .andThen(() => saveUser(user))  // Only runs if validation passes
  .andThen(() => sendWelcomeEmail(user));  // Only runs if save succeeds

// orElse provides fallback behavior when a result is Fail
const userData = primaryDataSource.getUser(id)
  .orElse(() => backupDataSource.getUser(id))  // Try backup if primary fails
  .orElse(() => createDefaultUser(id));  // Create default as last resort

๐Ÿ” Why These Methods Matter

These methods solve common pain points when working with the Result Pattern:

  • โœ… valueOrError: Simplified access to either success values or error values
  • โœ… match: Declarative, pattern-based handling of both success and failure cases
  • โœ… andThen: Cleaner composition of operations that depend on previous success
  • โœ… orElse: Elegant fallback strategies without complex conditional logic

๐Ÿ“‹ Complete Feature List

This release builds on our solid foundation:

  • โœ… Type-safe error handling with Ok<V, E> and Fail<V, E> classes
  • โœ… Powerful transformation methods like map, flatMap, and mapFails
  • โœ… Error aggregation with ResultUtils.combine
  • โœ… Flexible value extraction with unwrap, unwrapOr, and unwrapOrElse
  • โœ… Value/error swapping with flip
  • โœ… Direct value/error access with valueOrError
  • โœ… Elegant pattern matching with match
  • โœ… Enhanced flow control with and, andThen, or, and orElse

๐Ÿ› ๏ธ Migration Guide

This is a minor release with full backward compatibility. Simply update your package:

# npm
npm update @eicode/result-pattern

# yarn
yarn upgrade @eicode/result-pattern

# pnpm
pnpm update @eicode/result-pattern

๐Ÿ“š Usage Examples

Comprehensive Error Handling with Pattern Matching

function processPayment(paymentDetails) {
  return validatePaymentDetails(paymentDetails)
    .flatMap(details => processTransaction(details))
    .match({
      ok: receipt => ({
        success: true,
        receipt,
        message: "Payment processed successfully!"
      }),
      fail: errors => ({
        success: false,
        errors,
        message: "Payment processing failed"
      })
    });
}

Complex Operations with andThen and orElse

function getUserData(userId: string): Result<UserData, string> {
  return authenticateRequest()
    .andThen(() => checkUserPermissions(userId))
    .andThen(() => fetchUserFromPrimaryDB(userId))
    .orElse(() => fetchUserFromBackupDB(userId))
    .map(user => enrichUserData(user));
}

// Handle the result with valueOrError
const result = await getUserData("user-123");
const userOrError = result.valueOrError();

if (result.isOk) {
  renderUserProfile(userOrError);
} else {
  displayError(`Failed to load user: ${userOrError}`);
}

Form Validation with Combined Results

function validateForm(formData) {
  const name = validateName(formData.name);
  const email = validateEmail(formData.email);
  const password = validatePassword(formData.password);
  
  // Combine all validations to get all errors at once
  return ResultUtils.combine(name, email, password)
    .match({
      ok: ([validName, validEmail, validPassword]) => {
        return {
          success: true,
          data: { name: validName, email: validEmail, password: validPassword }
        };
      },
      fail: errors => {
        return {
          success: false,
          errors
        };
      }
    });
}

Made with ๐Ÿ’ป, โ˜•, and a bit of ๐Ÿช„ by @caiolandgraf and @JuniorBecari10