Level up your Typescript game, functionally - Part 3

prashanthr

Prashanth R.

Posted on November 25, 2023

Level up your Typescript game, functionally - Part 3

Welcome back to the final post in the series "Level up your Typescript game, functionally".

In the previous post, we looked at some functional concepts (like Monads) from the Scala programming language and re-implemented those concepts in Typescript with the Option and Either types.

Now let's look at another useful type from the Rust programming language.

The Result type

The extremely type safe Rust language exposes a type called Result that is very similar to the Either type (from Scala/Haskell) but it is exclusively used to model the result of an operation that can either be a Success or Failure (error).

This is what it looks like [ Source ]

pub enum Result<T, E> {
    Ok(T),
    Err(E),
}
Enter fullscreen mode Exit fullscreen mode

Example usage

let op: Result<i32, &str> = Ok(42);
assert_eq!(x.is_ok(), true);

let x: Result<i32, &str> = Err("Some error message");
assert_eq!(x.is_ok(), false);
Enter fullscreen mode Exit fullscreen mode

We can implement the Result type in Typescript too. Let's modify our Either implementation from our previous post and give it a go!

type Ok<T> = { value: T }
type Err<E> = { error: E }
// The Result Type
type Result<T, E = Error> = Ok<T> | Err<E>
Enter fullscreen mode Exit fullscreen mode

And the util functions to wrap objects

export const ok = <T>(value: T): Ok<T> => ({ value })
export const err = <E>(error: E): Err<E> => ({ error })
Enter fullscreen mode Exit fullscreen mode

And finally our matchers interface and match function

interface Matchers<T, E extends Error, R1, R2> {
    ok(value: T): R1
    err(error: E): R2
}

const match =
    <T, E extends Error, R1, R2>(matchers: Matchers<T, E, R1, R2>) =>
    (result: Result<T, E>) =>
        'value' in result
            ? matchers.ok(result.value)
            : matchers.err(result.error)
Enter fullscreen mode Exit fullscreen mode

As you can see this is very similar to the Either type implementation but uses Ok and Error instead of Left and Right.

And a practical example from before as follows

const getDataFromDB = 
  async (ctx: Context): Promise<Result<Data>> => {
    try {
      const result = await ctx.db.primary.getOne()
      return ok(result)
    } catch (err) {
      console.error('Error getting data from DB', err)
      return err(err)
    }
  }
// using pipe and andThen from the NodeJS 'ramda' package
const app = async () => {
   return pipe(
     getDataFromDB(ctx)
     andThen(
       match({
         err: (err) => throw err,
         ok: (value) => return value
       })
   )
}

Enter fullscreen mode Exit fullscreen mode

Summary

Through this entire series of posts, we saw that we can use pure functional concepts to re-write our Typescript application flows using appropriate types and make our code functionally aware thereby improving dev efficiency and utility especially when it comes to handling domain errors instead of throwing exceptions everywhere.

Takeaways and Resources

We learned 4 new functional types to help optimize our code and flows. They are namely ResultTuple, Option, Either and Result.

If you want to use any of these types mentioned in this series, check out this handy ts-utils NodeJS package that I created that encompasses these types as exports so you can use whatever variation makes sense for your use case. To install it simply run this command

npm i -S @universal-apps/ts-utils
Enter fullscreen mode Exit fullscreen mode

The advantage of the types we have discussed in detail in this series is that you can use as much or as little as your want and swap out portions of your codebase without affecting others.

However if you want to use a full fledged functional library with lots of utilities, I recommend checking out fp-ts and this handy cookbook that teaches you how to use it with examples. A newer library called EffectTS that also uses similar concepts and patterns has also been recently gaining popularity if you want to check that out.

Other libraries to check out are pratica and ramda

Last but not least if you want a good learning resource on Functional Programming, check out this series on Youtube.

Acknowledgements

I was heavily inspired by this post from Dan Imhoff on using Results in Typescript for this entire series of posts and extending the concepts.

Conclusion

Congrats on making it to the end of this final post in the series! You have leveled up once more 🍄🍄🍄 and completed your quest. Thanks for going on this journey with me.

If you found this post and/or series helpful, please upvote/react to it and share your thoughts and feedback in the comments.

Onwards and upwards 🚀

💖 💪 🙅 🚩
prashanthr
Prashanth R.

Posted on November 25, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related