Functional way for handling exceptions in typescript
Tags: typescript, functional, errors, try
Published: 2021-10-20 20:40:26

 Lets say we have the following simple function:

```typescript
const even = (a: number) => {
  if (a % 2 === 0) {
    return a
  }
  throw new Error(`value: ${a} is even`);
}
```

as you can see if the value is even we return the number else we throw an error. The normal way of handling this would be to wrap it inside a try-catch and handle the error. But when you have multiple functions this becomes tedious and error-prone.

 In the fp world instead of throwing errors all over the place, we convert them to data. This in typescript would look something like this:

```typescript
type Try<A> = Success<A> | Failure
```
where *Success<A>* is a container that wraps some value of type A and *Failure* is the alternative one that contains the error.

Let’s try to implement this structure! We will use a mix of OOP and FP, to create nicely chainable data structures. First, we will create an abstract class that will contain the types of our methods that our data structure will define

```typescript
abstract class Try<A> {
  abstract map<B>(this: Try<A>, fn: (a: A) => B): Try<B>
  abstract chain<B>(this: Try<A>, fn: (a: A) => Try<B>): Try<B>;
}
```

We defined two abstract methods: map and chain. The `map` function acts the same as it does in Array with one element. It takes the value and applies a function over it then "magically" it will be packed back into the array. 

Basically: ```typescript
[1].map(x => `${x}`).
```
In types: ```typescript
Array<Int> => (fn: (a: Int) => string) => Array<string>
```

The `chain` method is a bit more complicated. While the map just takes out the value, applies a function over it, and packs it back, with a chain it is your responsibility to pack it.
Our analog in an array of one element would be the following:
```typescript
[1].flatMap(x => [`${x * 2}`]).
```
In types: ```typescript
Array<Int> => (fn: (a: Int) => Array<string>) => Array<string>
```

You may ask why is this `chain` method useful anyway? As its name suggests we will use it to chain together multiple functions.

Before we continue implementing Success we need to introduce the concept of laziness.
The function arguments in javascript are called by value. What does this mean?
For example:


```typescript
function a(arg) {
   console.log(“hi”)
}

function b(a, b) {
   throws new Error(“Hello From the other side” + a + b)
}

a(b(1, 2))
```

What will happen here? Even if the argument of the function `a` was not used we still executed the function `b` and an error was thrown. How can we solve this? What if we would want to call it inside of `a`? 

Here our some helpers that solves our issue:


```typescript
// pass as thunk
type $<A> = () => A
function $<A>(a: A): $<A>{
  return () => a
}

// make function lazy
function $fn<A extends (...args: any) => any>(a: A): ((...p: Parameters<A>) => $<ReturnType<A>>) {
  return (...p: [Parameters<A>]) => () => {
    return a(...p)
  }
}
```




Next let us create a Success<A> that extends Try

```typescript
class Success<A> extends Try<A> {
  value: A
  constructor(a: A) {
    super()
    this.value = a;
  }

  static of<A>(value: A): Try<A> { return new Success(value); }

  map<B>(fn: (a: A) => B): Try<B> {
    const val = this.value;
    const x = $fn(fn)(val);
    return mkTry<B>(x)
  }

  chain<B>(fn: (a: A) => Try<B>): Try<B> {
    return fn(this.value);
  }
}
```

And Failure:

```typescript
class Failure<A> extends Try<A> {
  value: Error;
  constructor(e: Error) {
    super();
    this.value = e;
  }

  static of<A>(value: Error): Try<A> { return new Failure(value); }

  map<B>(fn: (a: A) => B): Try<B> {
    return Failure.of(this.value); 
  }

  chain<B>(fn: (a: A) => Try<B>): Try<B> {
    return Failure.of(this.value)
  }
}
```

Lets make a helper function to make our life easier:

```typescript
function mkTry<A>(value: $<A>): Try<A> {
    try {
      const a = value();
      return Success.of(a)
    } catch (error) {
      return Failure.of(error as Error)
    }
  }
```


With this in place now we have a mechanism to safely chain and execute our code.

Example:


```typescript
// // define a simple function that throws an error
const x = (a: number) => {
  if (a % 2 === 0) {
    return a
  }
  throw new Error(`value: ${a} is even`);
}

const div4 = (a: number) => {
  if (a % 4 === 0) {
    return a
  }
  throw new Error(`value: ${a} is not dividible by 4`);
}

// make it lazy
const lazyX = $fn(x)
const lazyDiv = $fn(div4)

// // wrap inside try, map chain
const a1 = Try.lift(12)
  .chain(a => mkTry(lazyX(a)))
  .map(b => (b * 2) - 4)
  .chain(a => mkTry(lazyDiv(a)));
console.log(a1);
```

In this example we defined some functions that can throw an error, then we made them lazy and wrapped them with Try using mkTry data constructor. 

Hope this helped a bit :) For any question leave a comment.  

For full implementation see: https://gist.github.com/lupuszr/f73baa7ef559f77e6e847ba75ed97182