OptionAsync
AsyncOption
represents a Promise
that never rejects of an asynchronous optional value.
Every AsyncOption
resolves to either Option.Some
, containing a value, or Option.None
, which is empty. It allows you to chain the same methods as an Option
, but in an asynchronous context.
Constructors
some
Constructs an AsyncOption
that resolves to an Option.Some
containing a value.
import { AsyncOption } from 'funkcia';
// ┌─── AsyncOption<number>
// â–¼
const option = AsyncOption.some(10);
// Output: Promise<Some(10)>
of
Constructs an AsyncOption
that resolves to a Some
Option
containing a value.
import { AsyncOption } from 'funkcia';
declare const divisor: number;
// ┌─── AsyncOption<number>
// â–¼
const option = AsyncOption.of(10);
none
Constructs an AsyncOption
that resolves to a None
Option
.
import { AsyncOption } from 'funkcia';
function rateLimit(clientId: ClientId, ip: IpAddress): AsyncOption<ClientId> {
const attempts = cache.get(`ratelimit:${clientId}:${ip}`)
if (attempts.total > 10) {
return AsyncOption.none();
}
return AsyncOption.some(clientId);
}
fromNullable
Constructs an AsyncOption
from a nullable value.
If the value is null
or undefined
, resolves to an Option.None
. Otherwise, resolves to an Option.Some
with the value.
import { AsyncOption } from 'funkcia';
declare const user: User | null
// ┌─── AsyncOption<User>
// â–¼
const option = AsyncOption.fromNullable(user);
fromFalsy
Constructs an AsyncOption
from a falsy value.
If the value is falsy, resolves to a None
. Otherwise, resolves to a Some
with the value.
import { AsyncOption } from 'funkcia';
function getEnv(variable: string): string {
return process.env[variable] ?? '';
}
// ┌─── AsyncOption<string>
// â–¼
const option = AsyncOption.fromFalsy(getEnv('BASE_URL'));
try
Constructs an AsyncOption
from a Promise
that may reject.
If the promise rejects, or resolves to null
or undefined
, resolves to an Option.None
. Otherwise, resolves to an Option.Some
with the value.
import { AsyncOption } from 'funkcia';
declare async function findUserById(id: string): Promise<User | null>
// ┌─── AsyncOption<User>
// â–¼
const option = AsyncOption.try(() => findUserById('user_123'));
// Output: Promise<Some(User)>
promise
Constructs an AsyncOption
from a Promise
that returns an Option
, and never rejects.
import { AsyncOption } from 'funkcia';
declare async function findUserById(id: string): Promise<Option<User>>
// ┌─── AsyncOption<User>
// â–¼
const option = AsyncOption.promise(() => findUserById('user_123'));
// Output: Promise<Some(User)>
liftPromise
Lifts a Promise
that resolves to an Option
or nullable value to a function that returns an AsyncOption
.
import { AsyncOption } from 'funkcia';
// With Option return type
declare async function findUserById(id: string): Promise<Option<User>>
// ┌─── (id: string) => AsyncOption<User>
// â–¼
const safeFindUserById = AsyncOption.liftPromise(findUserById);
// ┌─── AsyncOption<User>
// â–¼
const user = safeFindUserById('user_123');
// With nullable return type
declare async function findUserById(id: string): Promise<User | null>
// ┌─── (id: string) => AsyncOption<User>
// â–¼
const safeFindUserById = AsyncOption.liftPromise(findUserById);
// ┌─── AsyncOption<User>
// â–¼
const user = safeFindUserById('user_123');
predicate
Returns a function that asserts that a value passes the test implemented by the provided function. Can create an AsyncOption
that resolves to either Some
with a narrowed type or None
.
import { AsyncOption } from 'funkcia';
// With type guard
declare const input: Shape;
// ┌─── (shape: Shape) => AsyncOption<Circle>
// â–¼
const ensureCircle = AsyncOption.predicate(
(shape: Shape): shape is Circle => shape.kind === 'circle',
);
// ┌─── AsyncOption<Circle>
// â–¼
const option = ensureCircle(input);
// With regular predicate
// ┌─── (value: number) => AsyncOption<number>
// â–¼
const ensurePositive = AsyncOption.predicate(
(value: number) => value > 0,
);
// ┌─── AsyncOption<number>
// â–¼
const option = ensurePositive(input);
Combinators
values
Given an array of AsyncOption
s, returns an array containing only the values inside Some
.
import { AsyncOption } from 'funkcia';
// ┌─── number[]
// â–¼
const output = await AsyncOption.values([
AsyncOption.some(1),
AsyncOption.none<number>(),
AsyncOption.some(3),
]);
// Output: [1, 3]
zip
Combines two AsyncOption
s into a single AsyncOption
containing a tuple of their values, if both AsyncOption
s are Some
variants, otherwise, returns None
.
import { AsyncOption } from 'funkcia';
const first = AsyncOption.some('hello');
const second = AsyncOption.some('world');
// ┌─── AsyncOption<[string, string]>
// â–¼
const strings = first.zip(second);
// Output: Promise<Some(['hello', 'world'])>
zipWith
Combines two AsyncOption
s into a single AsyncOption
. The new value is produced by applying the given function to both values, if both AsyncOption
s are Some
variants, otherwise, returns None
.
import { AsyncOption } from 'funkcia';
const first = AsyncOption.some('hello');
const second = AsyncOption.some('world');
// ┌─── AsyncOption<string>
// â–¼
const greeting = first.zipWith(second, (a, b) => `${a} ${b}`);
// Output: Promise<Some('hello world')>
Conversions
then
Attaches a callback for the resolution of the Promise inside the AsyncOption
.
import { AsyncOption } from 'funkcia';
declare function findUserById(id: string): AsyncOption<User>
// ┌─── Option<User>
// â–¼
const option = await AsyncOption.of(user);
// Output: Some(User)
match
Returns a promise that compares the underlying Option
against the possible patterns, and then execute code based on which pattern matches.
import { AsyncOption } from 'funkcia';
declare function readFile(path: string): AsyncOption<string>;
declare function parseJsonFile(contents: string): AsyncOption<FileContent>;
// ┌─── string
// â–¼
const userGreeting = await readFile('data.json')
.andThen(parseJsonFile)
.match({
Some(contents) {
return processFile(contents);
},
None() {
return 'File is invalid JSON';
},
});
unwrap
Rejects the promise with UnwrapError
if the Option
is None
.
Returns a promise that unwraps the underlying Option
value.
import { AsyncOption } from 'funkcia';
// ┌─── User
// â–¼
const user = await AsyncOption.some(databaseUser).unwrap();
const team = await AsyncOption.none().unwrap();
// Output: Uncaught exception: 'called "Option.unwrap()" on a "None" value'
unwrapOr
Returns a promise that unwraps the underlying Option
value.
If the promise resolves to an Option.None
, returns the result of the provided callback.
import { AsyncOption } from 'funkcia';
// ┌─── string
// â–¼
const baseUrl = await AsyncOption.some(process.env.BASE_URL)
.unwrapOr(() => 'http://localhost:3000');
// Output: 'https://funkcia.lukemorales.io'
const apiKey = await AsyncOption.none()
.unwrapOr(() => 'sk_test_9FK7CiUnKaU');
// Output: 'sk_test_9FK7CiUnKaU'
unwrapOrNull
Returns a promise that unwraps the value of the underlying Option
if it is an Option.Some
, otherwise returns null
.
import { AsyncOption } from 'funkcia';
// ┌─── User | null
// â–¼
const user = await AsyncOption.some(databaseUser).unwrapOrNull();
unwrapOrUndefined
Returns a promise that unwraps the value of the underlying Option
if it is an Option.Some
, otherwise returns undefined
.
import { AsyncOption } from 'funkcia';
// ┌─── User | undefined
// â–¼
const user = await AsyncOption.some(databaseUser).unwrapOrUndefined();
expect
Rejects the promise with the provided Error if the Option
is None
.
Returns a promise that unwraps the underlying Option
value.
import { AsyncOption } from 'funkcia';
declare function findUserById(id: string): AsyncOption<User>;
// ┌─── User
// â–¼
const user = await findUserById('user_123').expect(
() => new UserNotFound(userId),
);
const anotherUser = await findUserById('invalid_id').expect(
() => new UserNotFound('team_123'),
);
// Output: Uncaught exception: 'User not found: "user_123"'
contains
Returns a Promise that verifies if the Option
contains a value that passes the test implemented by the provided function.
import { AsyncOption } from 'funkcia';
// ┌─── boolean
// â–¼
const isPositive = await AsyncOption.some(10).contains(num => num > 0);
// Output: true
toAsyncResult
Converts the AsyncOption
to an AsyncResult
. Can provide custom error handling.
import { AsyncOption } from 'funkcia';
declare function readFile(path: string): AsyncOption<string>;
declare function parseJsonFile(contents: string): AsyncOption<FileContent>;
// ┌─── AsyncResult<FileContent, NoValueError>
// â–¼
const asyncFile = readFile('data.json')
.andThen(parseJsonFile)
.toAsyncResult();
// Output: Promise<Ok(FileContent)>
// ┌─── AsyncResult<FileContent, InvalidFile>
// â–¼
const asyncFile = readFile('data.json')
.andThen(parseJsonFile)
.toAsyncResult(() => new InvalidFile('data.json'));
// Output: Promise<Ok(FileContent)>
toArray
Returns a Promise that converts the underlying Option
to an array.
import { AsyncOption } from 'funkcia';
// ┌─── number[]
// â–¼
const output = await AsyncOption.some(10).toArray();
// Output: [10]
Transformations
map
Applies a callback function to the value of the AsyncOption
when it is Some
, returning a new AsyncOption
containing the new value.
import { AsyncOption } from 'funkcia';
// ┌─── AsyncOption<number>
// â–¼
const option = AsyncOption.some(10).map(number => number * 2);
// Output: Promise<Some(20)>
andThen
Applies a callback function to the value of the AsyncOption
when it is Some
, and returns the new value. Can work with both Option
and AsyncOption
returns.
import { AsyncOption } from 'funkcia';
// With Option return
declare function readFile(path: string): AsyncOption<string>;
declare function parseJsonFile(contents: string): Option<FileContent>;
// ┌─── AsyncOption<FileContent>
// â–¼
const option = readFile('data.json').andThen(parseJsonFile);
// With AsyncOption return
declare function parseJsonFileAsync(contents: string): AsyncOption<FileContent>;
// ┌─── AsyncOption<FileContent>
// â–¼
const option = readFile('data.json').andThen(parseJsonFileAsync);
filter
Asserts that the AsyncOption
value passes the test implemented by the provided function. Can narrow types.
import { AsyncOption } from 'funkcia';
// With type guard
declare const input: Shape;
// ┌─── AsyncOption<Circle>
// â–¼
const circle = AsyncOption.of(input).filter(
(shape): shape is Circle => shape.kind === 'circle',
);
// With regular predicate
// ┌─── AsyncOption<User>
// â–¼
const option = AsyncOption.of(user).filter((user) => user.age >= 21);
Fallbacks
or
Replaces the current AsyncOption
with the provided fallback AsyncOption
when it is None
.
import { AsyncOption } from 'funkcia';
// Output: Promise<Some('Paul')>
const option = AsyncOption.some('Paul')
.or(() => AsyncOption.some('John'));
// Output: Promise<Some('John')>
const greeting = AsyncOption.none()
.or(() => AsyncOption.some('John'));
firstSomeOf
Resolves to the first AsyncOption.Some
value in the iterable. If all values are AsyncOption.None
, resolves to None
.
import { AsyncOption } from 'funkcia';
interface Contacts {
primary: AsyncOption<string>;
secondary: AsyncOption<string>;
emergency: AsyncOption<string>;
}
declare const contacts: Contacts;
// ┌─── AsyncOption<string>
// â–¼
const option = AsyncOption.firstSomeOf([
contacts.primary,
contacts.secondary,
contacts.emergency,
]);
Comparisons
is
Asserts that an unknown value is an AsyncOption
.
import { AsyncOption } from 'funkcia';
declare const maybeAnAsyncOptionWithUser: unknown;
if (AsyncOption.is(maybeAnAsyncOptionWithUser)) {
// ┌─── AsyncOption<unknown>
// â–¼
const user = maybeAnAsyncOptionWithUser.filter(isUser);
// â–²
// └─── AsyncOption<User>
}
Other
tap
Calls the function with the AsyncOption
value, then returns the AsyncOption
itself. The return value of the provided function is ignored.
import { AsyncOption } from 'funkcia';
// ┌─── AsyncOption<number>
// â–¼
const option = AsyncOption.some(10).tap((value) => console.log(value)); // LOG: 10
Last updated
Was this helpful?