fp-ts in actionš
š 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.