Skip to content

Future

A Future is like a Promise, but it’s lazy and has a type for the catch cases by using an Either as the value.

You can use map and flatMap and the functions will apply to the Either contained in the Future when the Future is executed.

import { Future, pipe } from "@jvlk/fp-tsm"
import { z } from "npm:zod"
const data = z.array(z.string())
const result = pipe(
// fetch the data and depending on the .ok property of the response, return a Right or Left
Future.fetch("https://baconipsum.com/api/?type=meat-and-filler"),
// fromPromise uses a try/catch under the hood so if res.json() fails, it will return a Left with that error
Future.flatMap((res) => Future.fromPromise(res.json())),
Future.flatMap((res) => {
// parse the data with zod, if it fails, it will return a Left with the error
const parsed = data.safeParse(res)
return parsed.success
? Future.right(parsed.data)
: Future.left(parsed.error)
})
)
// nothing has executed yet, so no network request has been made!
await result().then(console.log)
// Now the Future is executed, and the result is either a Right with the data or a Left with the error

Create a Future from an Promise by using .then and .catch.

import { Future } from "@jvlk/fp-tsm"
const data = Future.fromPromise(Promise.resolve(42)) // Either.right(42)
const error = Future.fromPromise(Promise.reject("Error")) // Either.left("Error")

Create a Future that resolves to a Right value.

import { Future } from "@jvlk/fp-tsm"
const data = Future.right(42) // Either.right(42)

Create a Future that resolves to a Left value.

import { Future } from "@jvlk/fp-tsm"
const error = Future.left("Error") // Either.left("Error")

Maps over the Right value of a Future using the provided function. If the Future contains a Left value, it will be returned unchanged.

import { Future } from "@jvlk/fp-tsm"
const future = Future.right(42)
const doubled = Future.map(future, (n: number) => n * 2)// Future<never, number>
await doubled() // Either.right(84)
const error = Future.left("error")
const doubledError = Future.map(error, (n: number) => n * 2) // Future<string, number>
await doubledError() // Either.left("error")

Maps over the Right value of a Future using the provided function and flattens the result. If the Future contains a Left value, it will be returned unchanged.

import { Future } from "@jvlk/fp-tsm"
const future = Future.right(42)
const doubled = Future.flatMap(future, (n: number) => Future.right(n * 2))// Future<never, number>
await doubled() // Either.right(84)
const error = Future.left("error")
const doubledError = Future.flatMap(error, (n: number) => Future.right(n * 2)) // Future<string, number>
await doubledError() // Either.left("error")

Maps over the Left value of a Future using the provided function. If the Future contains a Right value, it will be returned unchanged.

import { Future } from "@jvlk/fp-tsm"
const future = Future.left("error")
const mapped = Future.mapLeft(future, (e: string) => new Error(e)) // Future<Error, never>
await mapped() // Either.left(Error("error"))
const success = Future.right(42)
const mappedSuccess = Future.mapLeft(success, (e: string) => new Error(e)) // Future<Error, number>
await mappedSuccess() // Either.right(42)

Maps over the Left value of a Future using the provided function and flattens the result. If the Future contains a Right value, it will be returned unchanged.

import { Future } from "@jvlk/fp-tsm"
const future = Future.left("error")
const mapped = Future.flatMapLeft(future, (e: string) => Future.left(new Error(e))) // Future<Error, never>
await mapped() // Either.left(Error("error"))
const success = Future.right(42)
const mappedSuccess = Future.flatMapLeft(success, (e: string) => Future.left(new Error(e))) // Future<Error, number>
await mappedSuccess() // Either.right(42)

Maps over both the Left and Right values of a Future using the provided functions.

import { Future } from "@jvlk/fp-tsm"
const future = Future.right(42)
const mapped = Future.bimap(
future,
(e: string) => new Error(e),
(n: number) => n * 2
)
await mapped() // Either.right(84)
const error = Future.left("error")
const mappedError = Future.bimap(
error,
(e: string) => new Error(e),
(n: number) => n * 2
)
await mappedError() // Either.left(Error("error"))

A wrapper for fetch that returns a Future<Response | TypeError, Response> and checks Response.ok to determine if the response is a success or failure.

If there is an issue with the fetch call itself (like a bad URL), it will return a TypeError in the Left of the Either.

import { Future } from "@jvlk/fp-tsm"
const result = Future.fetch("https://baconipsum.com/api/?type=meat-and-filler")