Using match with Option in Effect
Tags: effect, javascript, typescript, functional
Published: 2024-07-03 04:34:58

The `match` function in Effect-TS is a versatile utility that allows developers to handle cases of `Option` values (`Some` and `None`) in a functional and expressive manner. It provides a way to define actions or computations that should occur based on the presence or absence of a value within an `Option`. By using `match`, you can succinctly specify different behaviors for `Some` and `None` without the need for explicit conditional checks, thus making your code cleaner and easier to understand. This function enhances code readability and maintainability by encapsulating conditional logic in a declarative style.

## Example 1

Match an Option and provide different behaviors for `Some` and `None` using `O.match`.

This example demonstrates returning different messages based on whether the Option contains a value or not.

```typescript
import { Option as O, pipe } from 'effect';

function match_ex01() {
  const some = O.some(1);
  const none = O.none();

  const handleOption = O.match({
    onNone: () => 'Option is None',
    onSome: (value) => `Option contains: ${value}`,
  });

  console.log(handleOption(some)); // Output: Option contains: 1
  console.log(handleOption(none)); // Output: Option is None
}
```

## Example 2

Match an Option and perform different side effects based on whether it is `Some` or `None`.

This example demonstrates logging messages based on the presence of a value.

```typescript
function match_ex02() {
  const some = O.some(1);
  const none = O.none();

  pipe(
    some,
    O.match({
      onNone: () => console.log('Option is None'), // Log a message if the Option is None
      onSome: (value) => console.log(`Option contains: ${value}`), // Log the value if the Option is Some
    })
  ); // Output: Option contains: 1

  pipe(
    none,
    O.match({
      onNone: () => console.log('Option is None'), // Log a message if the Option is None
      onSome: (value) => console.log(`Option contains: ${value}`), // Log the value if the Option is Some
    })
  ); // Output: Option is None
}
```

## Example 3

Match an Option and return a default value if it is `None` using `O.match`.
This example demonstrates providing a default value for a `None` case.

```typescript
function match_ex03() {
  const some = O.some(1);
  const none = O.none();

  const getValueOrDefault = (
    option: O.Option<number>,
    defaultValue: number
  ): number =>
    pipe(
      option,
      O.match({
        onNone: () => defaultValue, // Return the default value if the Option is None
        onSome: (value) => value, // Return the contained value if the Option is Some
      })
    );

  console.log(getValueOrDefault(some, 0)); // Output: 1 (since some contains 1)
  console.log(getValueOrDefault(none, 0)); // Output: 0 (since none is None)
}
```

## Example 4

Match an Option and perform computations based on the contained value using `O.match`.

This example demonstrates different computations based on the presence of a value.

```typescript
function match_ex04() {
  const some = O.some(2);
  const none = O.none();

  const compute = O.match({
    onNone: () => 0, // Return 0 if the Option is None
    onSome: (value: number) => value * value, // Compute the square of the value if the Option is Some
  });

  console.log(compute(some)); // Output: 4 (since some contains 2 and 2*2 = 4)
  console.log(compute(none)); // Output: 0 (since none is None)
}
```

## Example 5
Match an Option with more complex types and return a message based on the presence of a value.

This example demonstrates matching an Option containing an object.

```typescript
function match_ex05() {
  const some = O.some({ key: 'value' });
  const none = O.none();

  const handleComplexOption = O.match<string, { key: string }>({
    onNone: () => 'No data available', // Return a message if the Option is None
    onSome: (obj) => `Data: ${obj.key}`, // Return the key of the object if the Option is Some
  });

  console.log(handleComplexOption(some)); // Output: Data: value
  console.log(handleComplexOption(none)); // Output: No data available
}
```

## Replacing `map` and `getOrElse` with `match`

Traditionally, handling optional values in functional programming might involve using `map` to transform a value within an `Option` if present, followed by `getOrElse` to provide a fallback value in case of `None`. However, the `match` function in Effect-TS offers a more streamlined and expressive approach to this pattern.

The `match` function consolidates the functionality of `map` and `getOrElse` into a single operation. Instead of separately defining transformations and fallbacks, `match` allows you to handle both `Some` and `None` cases within the same function call. This unified approach reduces boilerplate and improves code clarity.

### Example: Simplifying Code with `match`

Consider the following example where `map` and `getOrElse` are used:

```typescript
import { Option as O, pipe } from 'effect';

const option = O.some(5);

const result = pipe(
  option,
  O.map(value => value * 2),
  O.getOrElse(() => 0)
);
console.log(result); // Output: 10
```

In this example, map is used to double the value if it exists, and getOrElse provides a default value of 0 if the Option is None. This can be simplified using match with pipe syntax:

```typescript
import { Option as O, pipe } from 'effect';

const option = O.some(5);

const result = pipe(
  option,
  O.match({
    onSome: value => value * 2,
    onNone: () => 0
  })
);
console.log(result); // Output: 10
```

By using match, the transformation and fallback are defined in one place, making the logic easier to follow and reducing the potential for errors. This example illustrates how match not only replaces map and getOrElse but also enhances the maintainability and readability of the code dealing with optional values.

## Conclusion

In conclusion, the `match` function is an essential tool in the Effect-TS library that simplifies handling optional values with the `Option` type. By providing clear, type-safe ways to distinguish between `Some` and `None`, `match` helps avoid common errors associated with null checks and enhances the functional programming capabilities in TypeScript. As demonstrated through various examples, using `match` not only makes the code more robust but also significantly improves its readability and expressiveness. Adopting this pattern can lead to cleaner, more maintainable codebases where optional values are a common occurrence.