fp-ts in actionšŸš€

Liron Hazan
ITNEXT
Published in
3 min readJan 29, 2021

--

šŸ‘Š First post for 2021!

Recently I decided to adopt fp-ts lib on a side project.

What is Fp-ts?

Itā€™s a library that provides abstractions from typed functional languages that makes it easy to apply functional patterns when developing in TypeScript.

My motivation in adopting fp-ts was:

  • Iā€™ve been charmed by languages such Haskell and Rust and wanted to use some familiar ADTs in the code (Option/Maybe, Just/Some, Either/Result, None).
  • I liked the Error handling approach.
  • I wanted to figure out if it can really improve my typescript projects while enjoying the functional style.

An easy kickstart

Iā€™ve been reading the fp-ts docs and posts for a while so what was left is to pick a simple side project code, generalise it a bit and start using fp-ts :)

I picked a simple procedure I have that fetches data I manage in google-sheets tables as follows:

  • Read sheet credentials from private local file
  • Authenticate
  • run fetchTables which fetches all tables in parallel (each table has its own route)

Note: following recipes are super useful šŸ““

Letā€™s review the fetchTable function sig:

function fetchTable<T>(sheets: Sheets, range: any, spreadsheetId: any): Promise<T> 

fetchTable accepts 3 arguments and returns some value of some type T wrapped in a Promise.

But thereā€™s a better way of writing this function in a way that expresses the possibility of a failure.

fp-ts introduces Either:

The Either<E, A> type represents a computation that might fail with an error of type E or succeed with a value of type A

Letā€™s refactor the function to use it:

Task and TaskEither:

Task: asynchronous computation that yields a value of given type and **never fails** e.g:

const task1: Task<string> = () => Promise.resolve('task1')

Adding error handling:

TaskEither: asynchronous computation that may fail

tryCatch Constructs a new Either from a function that might throw. readCreds() is a function that will be executed in case of success and fail() will run on failure.

Pipe:

Being used in chain sequence of functions from left-to-right, first argument can be initial value, afterwards we pass functions in a point free style.

Fetching all as tasks sequence

Sequence could be an array of tasks, the following practical guide explains it well.

Letā€™s review the code:

In line 5 we define an inner async function that eventually process our fetch calls in case auth succeeded (line 21).

We can see that the tables fetch calls are mapped as tasks into a Task typed list (lines 8 + 9).

The tasks are passed to a function returned by array.sequence, that returns an async function (line 11).

We pipe the list of promises as initial value and the folding function to handle the result to either error case or success case (line 12ā€“21).

The full code can be found here, feel free to star ā­ļø if you find it useful!

Thatā€™s all for this post,

Ending thoughts:

I was having fun while adopting fp-ts I must say, but thereā€™s a small learning curve to pass before the writing starts to flow :)

Regarding if Iā€™ll adopt it in future projects a, for personal once probably will, there are some really cool abstractions and types in context of category theory that fp-ts provides that werenā€™t mentioned on this post that I really want to utilize as well.

Check out this wonderful series:

Thanks for reading šŸ™

Cheers, Liron.

--

--

"The more I learn, the more I realize how much I don't know"