@attio/fetchable v0.0.1-experimental.5
Fetchable
fetchable
is a library for explicitly handling errors and loading in Typescript and JavaScript.
Installation
> npm install @attio/fetchable
Concepts
Primitive states
There are three primitive states in fetchable
.
✅ Complete
A Complete<V>
is a simple JavaScript object which represents any kind of intact data.
import {complete} from "@attio/fetchable"
const completeNumber = complete(1) // Returns a Complete<1>
console.log(completeNumber.value) // 1
console.log(completeNumber.state) // "complete"
❌ Errored
An Errored<E>
is another JavaScript object which represents something that went wrong.
import {errored} from "@attio/fetchable"
const erroredThing = errored("Oops") // Returns an Errored<"Oops">
console.log(erroredThing.error) // "Oops"
console.log(erroredThing.state) // "errored"
⏳ Pending
A Pending
is another JavaScript object which represents some process which is in progress.
import {pending} from "@attio/fetchable"
const pendingThing = pending() // Returns a Pending
console.log(pendingThing.state) // "pending"
Higher order states
The fun comes when we start to mix up the three primitive states.
Result: Complete or Errored
A Result<V, E>
is an object which is either a Complete<V>
or an Errored<E>
. It represents the
outcome of a process which might succeed or fail.
import {isComplete} from "@attio/fetchable"
const result = doSynchronousThingWhichMightError() // Returns Result<number, "Oops">
if (isComplete(result)) {
console.log(result.value) // number
} else {
console.log(result.error) // "Oops"
}
Loadable: Complete or Pending
A Loadable<V>
is an object which is either a Complete<V>
or a Pending
. It represents the
outcome of an asynchronous process which cannot fail.
import {isComplete} from "@attio/fetchable"
const loadable = getStatusOfLongRunningProcess() // Returns Loadable<number>
if (isComplete(loadable)) {
console.log(loadable.value) // number
}
Fetchable: Complete or Pending or Errored
A Fetchable<V, E>
is an object which is either a Complete<V>
, Errored<E>
or Pending
. It
represents the outcome of an asynchronous process which can fail.
Fetchable
is most often seen in declarative front-end code where we don't want to expose promises.
import {isComplete, isErrored} from "@attio/fetchable"
const fetchable = getStatusOfLongRunningProcessWhichMightFail() // Returns Fetchable<number, "Oops">
if (isComplete(fetchable)) {
console.log(fetchable.value) // number
} else if (isErrored(fetchable)) {
console.log(fetchable.error) // "Oops"
}
AsyncResult
An AsyncResult<V, E>
is a promise of a Result<V, E>
. Complete<V>
, Errored<E>
or Pending
.
It is most often seen in imperative code where we use promises for asynchronous processes.
import {isComplete, isErrored} from "@attio/fetchable"
const asyncResult = runAsyncProcessWhichMightFail() // Returns AsyncResult<number, "Oops">
asyncResult.then(result => {
if (isComplete(result)) {
console.log(result.value) // number
} else if (isErrored(result)) {
console.log(result.error) // "Oops"
}
})
Transformations
fetchable
provides functional utilities for working with these objects without explicitly checking
which state they're in.
map
import {map} from "@attio/fetchable"
const fetchable = getStatusOfLongRunningProcessWhichMightFail() // Returns Fetchable<number, "Oops">
// Increments the fetchable if it's complete.
// Returns Fetchable<number, "Oops">
const incrementedFetchable = map(fetchable, (number) => number + 1)
bind
import {map} from "@attio/fetchable"
const fetchable = getStatusOfLongRunningProcessWhichMightFail() // Returns Fetchable<number, "Oops">
// Increments the fetchable if it's complete and not zero.
// Returns Fetchable<number, "Oops" | "Unexpected zero">
const incrementedFetchable = bind(fetchable, (number) =>
number === 0 ? errored("Unexpected zero") : complete(number + 1)
)
combine
Arrays
import {combine} from "@attio/fetchable"
const fetchable1 = getStatusOfLongRunningProcessWhichMightFail() // Returns Fetchable<number, "Oops">
const fetchable2 = doSynchronousThingWhichMightError() // Returns Result<string, "Eek">
// If both fetchables are complete then their values will be returned in a complete array.
// Returns Fetchable<[number, string], "Oops" | "Eek">
const combinedFetchable = combine([fetchable1, fetchable2])
Objects
import {combine} from "@attio/fetchable"
const fetchableA = getStatusOfLongRunningProcessWhichMightFail() // Returns Fetchable<number, "Oops">
const fetchableB = doSynchronousThingWhichMightError() // Returns Result<string, "Eek">
// If both fetchables are complete then their values will be returned in a new object.
// Returns Fetchable<{a: number, b: string}, "Oops" | "Eek">
const combinedFetchable = combine({a: fetchable1, b: fetchable2})
combineAsync
Like Promise.all
for AsyncResult
s. It takes multiple AsyncResult
s and resolves when they all
resolve with Complete
s or when one resolves with an Errored
.
Arrays
import {combineAsync} from "@attio/fetchable"
const asyncResult1 = runAsyncProcessWhichMightFail() // Returns AsyncResult<number, "Oops">
const asyncResult2 = runAnotherAsyncProcessWhichMightFail() // Returns AsyncResult<string, "Eek">
// Returns Result<[number, string], "Oops" | "Eek">
const combinedResult = await combineAsync([asyncResult1, asyncResult2])
Objects
import {combine} from "@attio/fetchable"
const asyncResultA = runAsyncProcessWhichMightFail() // Returns AsyncResult<number, "Oops">
const asyncResultB = runAnotherAsyncProcessWhichMightFail() // Returns AsyncResult<string, "Eek">
// If both fetchables are complete then their values will be returned in a new object.
// Returns Result<{a: number, b: string}, "Oops" | "Eek">
const combinedResult = await combineAsync({a: asyncResultA, b: asyncResultB})
6 months ago
7 months ago
7 months ago
7 months ago