Skip to main content

AsyncData<Value>

The AsyncData type enables representing asynchronous flows (e.g. requests). The type represents the state as a discriminating union, avoiding manual management for loading flows.

AsyncData can have three possible states:

  • NotAsked
  • Loading
  • Done(value)

Create an AsyncData value

To create an async data, use the NotAsked, Loading and Done constructors:

Examples
import { AsyncData } from "@swan-io/boxed";

const notAsked = AsyncData.NotAsked();

const loading = AsyncData.Loading();

const done = AsyncData.Done(1);

Methods

The async data type provides a few manipulation functions:

.map(f)

AsyncData<A>.map<B>(f: (value: A) => B): AsyncData<B>

If the asyncData is Done(value) returns Done(f(value)), otherwise returns the async data.

Examples
AsyncData.Done(2).map((x) => x * 2);
// AsyncData.Done<4>

AsyncData.Loading().map((x) => x * 2);
// AsyncData.Loading

AsyncData.NotAsked().map((x) => x * 2);
// AsyncData.NotAsked

.flatMap(f)

AsyncData<A>.flatMap<B>(f: (value: A) => AsyncData<B>): AsyncData<B>

If the asyncData is Done(value) returns f(value), otherwise returns the async data.

Examples
AsyncData.Done(3).flatMap((x) =>
x > 2 ? AsyncData.NotAsked() : AsyncData.Done(2),
);
// AsyncData.NotAsked

AsyncData.Done(1).flatMap((x) =>
x > 2 ? AsyncData.NotAsked() : AsyncData.Done(2),
);
// AsyncData.Done<2>

AsyncData.NotAsked().flatMap((x) =>
x > 2 ? AsyncData.NotAsked() : AsyncData.Done(2),
);
// AsyncData.NotAsked

AsyncData.Loading().flatMap((x) =>
x > 2 ? AsyncData.NotAsked() : AsyncData.Done(2),
);
// AsyncData.Loading

.getWithDefault(defaultValue)

AsyncData<A>.getWithDefault(defaultValue: A): A

If the async data is Done(value) returns value, otherwise returns defaultValue.

Examples
AsyncData.Done(2).getWithDefault(1);
// 2

AsyncData.Loading().getWithDefault(1);
// 1

AsyncData.NotAsked().getWithDefault(1);
// 1

.get()

AsyncData<A>.get(): A

Returns the value contained in Done(value). Only usable within a isDone() check.

Examples
const value = asyncData.get();
// does not compile

if (asyncData.isDone()) {
const value = asyncData.get();
// value
}

.isDone()

AsyncData<A>.isDone(): boolean

Type guard. Checks if the option is Done(value)

Examples
AsyncData.Done(2).isDone();
// true

AsyncData.Loading().isDone();
// false

AsyncData.NotAsked().isDone();
// false

if (asyncData.isDone()) {
const value = asyncData.get();
}

.isLoading()

AsyncData<A>.isLoading(): boolean

Type guard. Checks if the option is Loading

Examples
AsyncData.Done(2).isLoading();
// false

AsyncData.Loading().isLoading();
// true

AsyncData.NotAsked().isLoading();
// false

.isNotAsked()

AsyncData<A>.isNotAsked(): boolean

Type guard. Checks if the option is NotAsked

Examples
AsyncData.Done(2).isNotAsked();
// false

AsyncData.Loading().isNotAsked();
// false

AsyncData.NotAsked().isNotAsked();
// true

.toOption()

AsyncData<A>.toOption(): Option<A>

If the result is Done(value) returns Some(value), otherwise returns None.

Examples
Result.Done(2).toOption();
// Option.Some<2>

Result.Loading().toOption();
// Option.None

Result.NotAsked().toOption();
// Option.None

.match()

AsyncData<A>.match<B>(config: {
Done: (value: A) => B;
Loading: () => B;
NotAsked: () => B;
}): B;

Match the async data state

Examples
const valueToDisplay = result.match({
Done: (value) => value,
Loading: () => "Loading ...",
NotAsked: () => "",
});

.tap(func)

AsyncData<A>.tap(func: (asyncData: AsyncData<A>) => unknown): AsyncData<A>

Executes func with asyncData, and returns asyncData. Useful for logging and debugging.

Examples
asyncData.tap(console.log).map((x) => x * 2);

Statics

AsyncData.isAsyncData(value)

isAsyncData(value: unknown): boolean

Type guard, checks if the provided value is an asyncData.

Examples
AsyncData.isAsyncData(AsyncData.Done(1));
// true

AsyncData.isAsyncData([]);
// false

AsyncData.all(asyncDatas)

all(asyncDatas: Array<AsyncData<A>>): AsyncData<Array<A>>

Turns an "array of asyncDatas of value" into a "asyncData of array of value".

Examples
AsyncData.all([AsyncData.Done(1), AsyncData.Done(2), AsyncData.Done(3)]);
// AsyncData.Done<[1, 2, 3]>

AsyncData.all([Result.NotAsked(), AsyncData.Done(2), AsyncData.Done(3)]);
// AsyncData.NotAsked

AsyncData.all([Result.Loading(), AsyncData.Done(2), AsyncData.Done(3)]);
// AsyncData.Loading

AsyncData.allFromDict(asyncDatas)

allFromDict(asyncDatas: Dict<AsyncData<A>>): AsyncData<Dict<A>>

Turns a "dict of asyncDatas of value" into a "asyncData of dict of value".

Examples
AsyncData.allFromDict({
a: AsyncData.Done(1),
b: AsyncData.Done(2),
c: AsyncData.Done(3),
});
// AsyncData.Done<{a: 1, b: 2, c: 3}>

AsyncData.allFromDict({
a: Result.NotAsked(),
b: AsyncData.Done(2),
c: AsyncData.Done(3),
});
// AsyncData.NotAsked

AsyncData.allFromDict({
a: Result.Loading(),
b: AsyncData.Done(2),
c: AsyncData.Done(3),
});
// AsyncData.Loading

TS Pattern interop

Examples
import { match, P } from "ts-pattern";
import { AsyncData } from "@swan-io/boxed";

match(asyncData)
.with(AsyncData.P.Done(P.select()), (value) => console.log(value))
.with(AsyncData.P.Loading, () => "Loading ...")
.with(AsyncData.P.NotAsked, () => "")
.exhaustive();

Cheatsheet

MethodInputFunction inputFunction outputReturned value
mapDone(x)xyDone(y)
mapLoading()not providednot executedLoading()
mapNotAsked()not providednot executedNotAsked()
flatMapDone(x)xDone(y)Done(y)
flatMapDone(x)xLoading()Loading()
flatMapDone(x)xNotAsked()NotAsked()
flatMapLoading()not providednot executedLoading()
flatMapNotAsked()not providednot executedNotAsked()