A simple IO monad.

fp, functional, typescript, monad, io, lazy, promise
npm install @navidjalali/io@1.1.1


🍉 IO

A small library that makes promises less eager 🥔

IO<A> is a lightweight wrapper around () => Promise<A> with some useful combinators.

🔧 Installation

npm install @navidjalali/io

⚡️ How to make an IO

You can make a new IO using one of the following ways:

🏋🏻‍♂️ Lifting a pure value into an IO:

You can make a successful or failed IO out of a pure value.

👷🏻‍♂️ Using the constructor:

This is very similar to creating a normal Promise.

new IO<A>((resolve, reject) => {
    // ...
🦆 From a thunk that returns a promise

Any promise can be wrapped into an IO.

IO.fromThunk(() => fetch('/api/v1/posts'))
🍩 From a function

Exceptions thrown by the function will be lifted into failures.

const unsafeFunction = () => {
    // Unsafe code


🤔 How to evaluate an IO?

Simply call .run(). This will create a normal Promise.


Any IO that will return some Union type A | InProgress can be polled using IO.poll. This will rerun the IO until it succeeds with a result of type A.

const checkProgress: IO<Result | InProgress> = IO.fromThunk(
    () => fetch('/api/v1/progress/poll')
).flatMap(_ => _.json())
const result: IO<Result> = IO.poll(checkProgress, 100)


You can schedule an IO to run later using the scheduleOnce and scheduleForever combinators. You can also make more complicated scheduling logic yourself using IO.sleep and recursion.

🔁 Retries

You can retry an IO using a RetryPolicy. Currently you can only pick between Spaced and ExponentialWithBackoff

IO.fromThunk(() => fetch('/api/v1/posts'))
    .retry(RetryPolicies.spaced(100, 3))


You can effectively get a rejection if your effect runs longer than a specified period using the timeout combinator but please keep in mind that this WILL NOT cancel the Promise created from running this effect or interrupt its finalizers. Hopefully I will make this behaviour better soon.

🌈 More!

There's more you can do. Feel free to check the code, and contribute if you find a new usecase that can be covered!