PendingOption
PendingOption represents an
Option, whose value is not yet resolved (thus, pending). Due to
the asynchronous nature of JavaScript, a single Option type is
not enough to represent the conditional value, PendingOption closes this gap and offers
rich set of methods, similar to ones an Option has.
PendingOption implements PromiseLike<Option<T>> interface, which means that
it can be Awaited as a regular Promise.
In order to access the value of PendingOption, you need to await it, which
will resolve it to either Some<T> or None variant. Once resolved, you can
use the methods available on Option to work with the value.
Constructors
pendingNone()- creates aPendingOptionthat resolves toNonevariant.pendingSome<T>(value: T | Promise<T>)- creates aPendingOptionthat resolves toSome<T>variant.pendingOption(optionOrFactory: Option<T> | Promise<Option<T>> | (() => Option<T> | Promise<Option<T>>))- creates aPendingOptionthat resolves to the providedOption.
Methods
and
and<U>(x: Option<U> | Promise<Option<U>>): PendingOption<Awaited<U>>
Returns a PendingOption with None if this option resolves to None,
otherwise returns a PendingOption with x.
This is the asynchronous version of and.
If x is a Promise and rejects, None is returned.
const x = pendingOption(some(2));
const y = pendingOption(none<number>());
expect(await x.and(some(3))).toStrictEqual(some(3));
expect(await x.and(Promise.resolve(some(3)))).toStrictEqual(some(3));
expect(await x.and(none())).toStrictEqual(none());
expect(await x.and(Promise.resolve(none()))).toStrictEqual(none());
expect(await y.and(some(3))).toStrictEqual(none());
expect(await y.and(Promise.resolve(none()))).toStrictEqual(none());
andThen
andThen<U>(f: (x: T) => Option<U> | Promise<Option<U>>): PendingOption<Awaited<U>>
Returns a PendingOption with None if this Option resolves to None,
otherwise applies f to the resolved value and returns the result.
This is the asynchronous version of andThen.
If f rejects or throws, None is returned.
const x = pendingOption(some(2));
const y = pendingOption(none<number>());
expect(await x.andThen((n) => some(n * 2))).toStrictEqual(some(4));
expect(await x.andThen((n) => Promise.resolve(some(n * 2)))).toStrictEqual(some(4));
expect(await x.andThen((_) => none())).toStrictEqual(none());
expect(await y.andThen((n) => some(n * 2))).toStrictEqual(none());
combine
Combines this PendingOption with other Option or PendingOption
instances into a single PendingOption containing a tuple of resolved values.
The combine method takes an arbitrary number of Option or PendingOption
instances. It resolves all inputs and returns a PendingOption that, when
resolved, contains an Option with a tuple of their values if all resolve
to Some. If any input resolves to None, the result resolves to None.
The resulting tuple includes the resolved value of this PendingOption as
the first element, followed by the resolved values from the provided instances.
const a = pendingSome(1);
const b = some(Promise.resolve("hi"));
const c = none<Error>();
const d = pendingNone<Promise<Date>>();
const e = a.combine(b, c, d); // PendingOption<[number, string, Error, Date]>
filter
filter(f: (x: T) => boolean | Promise<boolean>): PendingOption<T>
Returns a PendingOption with None if the option resolves to None,
otherwise calls f with the resolved value and returns a PendingOption
with the original value if f resolves to true, or None otherwise.
This is the asynchronous version of filter.
If f rejects or throws, None is returned.
const x = pendingOption(some(2));
const y = pendingOption(none<number>());
expect(await x.filter((n) => n > 0)).toStrictEqual(some(2));
expect(await x.filter((n) => Promise.resolve(n < 0))).toStrictEqual(none());
expect(await y.filter((_) => true)).toStrictEqual(none());
flatten
Flattens a PendingOption of a PendingOption or Option, resolving nested pending states.
This is the asynchronous version of flatten.
If inner Option is wrapped in a Promise and rejects,
flattened PendingOption with None is returned.
const option1: PendingOption<Option<number>> = getPendingOption();
option1.flatten(); // PendingOption<number>
const option2: PendingOption<PendingOption<number>> = getPendingOption();
option2.flatten(); // PendingOption<number>
const option3: PendingOption<PendingOption<PendingOption<number>>> = getPendingOption();
option3.flatten(); // PendingOption<Option<number>>
inspect
inspect(f: (x: T) => unknown): PendingOption<T>
Calls f with the resolved value if the option is Some, then returns this
PendingOption unchanged. Useful for side effects.
This is the asynchronous version of inspect.
Returns a new PendingOption instance with the same value as the original,
rather than the exact same reference. The returned option is a distinct object,
preserving the original value.
const x = pendingOption(some(2));
const y = pendingOption(none<number>());
let sideEffect = 0;
expect(await x.inspect((n) => (sideEffect = n))).toStrictEqual(some(2));
expect(sideEffect).toBe(2);
expect(await y.inspect((n) => (sideEffect = n))).toStrictEqual(none());
expect(sideEffect).toBe(2); // Unchanged
iter
iter(): AsyncIterableIterator<Awaited<T>, Awaited<T>, void>
Returns an async iterator over the pending option’s value, yielding it if
it resolves to Some or nothing if it resolves to None.
- Yields exactly one item for a resolved
Some, or zero items for a resolvedNone. - Compatible with
for await...ofloops and async spread operators (with caution).
const x = some(42).toPending();
const y = none<number>().toPending();
const iterX = x.iter();
expect(await iterX.next()).toEqual({ value: 42, done: false });
expect(await iterX.next()).toEqual({ done: true });
const iterY = y.iter();
expect(await iterY.next()).toEqual({ done: true });
async function collect(iter: AsyncIterableIterator<number, number, void>) {
const result = [];
for await (const val of iter) result.push(val);
return result;
}
expect(await collect(x.iter())).toEqual([42]);
expect(await collect(y.iter())).toEqual([]);
map
map<U>(f: (x: T) => U): PendingOption<Awaited<U>>
Maps the resolved value with f, returning a PendingOption with the
result if Some, or None otherwise.
This is the asynchronous version of map.
If f throws or rejects, returns None.
const x = pendingOption(some(2));
const y = pendingOption(none<number>());
expect(await x.map((n) => n * 2)).toStrictEqual(some(4));
expect(await x.map((n) => Promise.resolve(n * 2))).toStrictEqual(some(4));
expect(await y.map((n) => n * 2)).toStrictEqual(none());
mapAll
mapAll<U>(f: (x: Option<T>) => Option<U> | Promise<Option<U>>): PendingOption<Awaited<U>>
Maps this option by applying a callback to its full state, executing the
callback for both Some and None, returning a new PendingOption.
Unlike andThen, which only invokes the callback for Some,
this method always calls f, passing the entire Option as its argument.
This is the asynchronous version of mapAll.
If f throws or returns a Promise that rejects, the newly
created PendingOption will resolve to a None.
const someOpt = pendingOption(some(42));
const noneOpt = pendingOption(none<number>());
const someMapped = someOpt.mapAll((opt) => Promise.resolve(some(opt.unwrapOr(0))));
expect(await someMapped).toStrictEqual(some(42));
const noneMapped = noneOpt.mapAll((opt) => Promise.resolve(some(opt.unwrapOr(0) + 1)));
expect(await noneMapped).toStrictEqual(some(1));
match
match<U, F = U>(f: (x: T) => U, g: () => F): Promise<Awaited<U | F>>
Matches the resolved option, returning f applied to the value if Some,
or g if None. Returns a Promise with the result.
This is the asynchronous version of match.
If f or g throws or returns a rejected Promise, the returned promise
rejects with the original error. In this case the caller is responsible
for handling the rejection.
Rejects with OptionError if f or g throws an exception or rejects,
original error will be set as OptionError.reason.
const x = pendingOption(some(2));
const y = pendingOption(none<number>());
expect(await x.match(n => n * 2, () => 0)).toBe(4);
expect(await y.match(n => n * 2, () => 0)).toBe(0);
await expect(y.match(n => n * 2, () => { throw new Error() })).rejects.toThrow(OptionError);
okOr
okOr<E>(y: Awaited<E>): PendingResult<T, E>
Converts to a PendingResult, using y as the error value if the
PendingOption resolves to None.
This is the asynchronous version of okOr.
const x = pendingOption(some(2));
const y = pendingOption(none<number>());
expect(await x.okOr("error")).toStrictEqual(ok(2));
expect(await y.okOr("error")).toStrictEqual(err("error"));
okOrElse
okOrElse<E>(mkErr: () => E | Promise<E>): PendingResult<T, E>
Converts to a PendingResult, using the result of mkErr
as the error value if this resolves to None.
This is the asynchronous version of okOrElse.
const x = pendingOption(some(2));
const y = pendingOption(none<number>());
expect(await x.okOrElse(() => "error")).toStrictEqual(ok(2));
expect(await y.okOrElse(() => Promise.resolve("error"))).toStrictEqual(err("error"));
or
or(x: Option<T> | Promise<Option<T>>): PendingOption<Awaited<T>>
Returns this PendingOption if it resolves to Some, otherwise
returns a PendingOption with x.
This is the asynchronous version of or.
If x is a Promise that rejects, None is returned.
const x = pendingOption(some(2));
const y = pendingOption(none<number>());
expect(await x.or(some(3))).toStrictEqual(some(2));
expect(await x.or(Promise.resolve(none()))).toStrictEqual(some(2));
expect(await y.or(some(3))).toStrictEqual(some(3));
expect(await y.or(Promise.resolve(none()))).toStrictEqual(none());
orElse
orElse(f: () => Option<T> | Promise<Option<T>>): PendingOption<Awaited<T>>
Returns this PendingOption if it resolves to Some, otherwise
returns a PendingOption with the result of f.
This is the asynchronous version of orElse.
If f throws or rejects, None is returned.
const x = pendingOption(some(2));
const y = pendingOption(none<number>());
expect(await x.orElse(() => some(3))).toStrictEqual(some(2));
expect(await y.orElse(() => some(1))).toStrictEqual(some(1));
expect(await y.orElse(() => Promise.resolve(some(3)))).toStrictEqual(some(3));
tap
tap(f: (x: Option<T>) => unknown): PendingOption<T>
Executes f with the resolved option, then returns a new PendingOption unchanged.
This is the asynchronous version of tap.
- If
fthrows or rejects, the error is ignored. - If
freturns a promise, the promise is not awaited before returning.
const x = pendingOption(some(42));
const y = pendingOption(none<number>());
let log = "";
expect(await x.tap((opt) => (log = opt.toString()))).toStrictEqual(some(42));
expect(log).toBe("Some { 42 }");
expect(await y.tap((opt) => (log = opt.toString()))).toStrictEqual(none());
expect(log).toBe("None");
transpose
transpose<U, E>(this: PendingOption<Result<U, E>>): PendingResult<Option<U>, E>
Transposes a PendingOption of a Result into a PendingResult containing an Option.
This is the asynchronous version of transpose.
Only available on PendingOptions that hold a Result value.
const x = pendingOption(none<Result<number, string>>());
const y = pendingOption(some<Result<number, string>>(ok(2)));
const z = pendingOption(some<Result<number, string>>(err("error")));
expect(await x.transpose()).toStrictEqual(ok(none()));
expect(await y.transpose()).toStrictEqual(ok(some(2)));
expect(await z.transpose()).toStrictEqual(err("error"));
xor
xor(y: Option<T> | Promise<Option<T>>): PendingOption<Awaited<T>>
Returns a PendingOption with Some if exactly one of this option or
y resolves to Some, otherwise returns a PendingOption with None.
This is the asynchronous version of xor.
If y is a Promise that rejects, None is returned.
const x = pendingOption(some(2));
const y = pendingOption(none<number>());
expect(await x.xor(some(3))).toStrictEqual(none());
expect(await x.xor(Promise.resolve(none()))).toStrictEqual(some(2));
expect(await y.xor(some(3))).toStrictEqual(some(3));
expect(await y.xor(Promise.resolve(none()))).toStrictEqual(none());