Skip to main content

Option

Type Option represents an optional value: every Option is either Some and contains a value, or None, and does not. Option types are very common, as they have a number of uses:

  • Initial values
  • Return value for otherwise reporting simple errors, where None is returned on error
  • Optional object fields
  • Optional function arguments
  • Swapping things out of difficult situations

Variants

Constructors

Methods

and

and<U>(x: Option<U>): Option<U>

Takes another Option and returns None if this options is None, otherwise returns provided option.

const x = some(2);
const y = none<number>();

expect(x.and(some(3))).toStrictEqual(some(3));
expect(x.and(none())).toStrictEqual(none());
expect(y.and(some(3))).toStrictEqual(none());
expect(y.and(none())).toStrictEqual(none());

andThen

andThen<U>(f: (x: T) => Option<U>): Option<U>

Takes a predicate function f that is called with current Option if it's Some, otherwise returns None without calling the predicate.


const x = some(2);
const y = none<number>();

expect(x.andThen(n => some(n * 2))).toStrictEqual(some(4));
expect(x.andThen(_ => { throw new Error() })).toStrictEqual(none());
expect(x.andThen(_ => none())).toStrictEqual(none());
expect(y.andThen(n => some(n * 2))).toStrictEqual(none());

clone

clone<U>(this: Option<Cloneable<U>>): Option<U>

Returns a clone of the Option.

note

Only available on Options with Cloneable values.

class CloneableClass implements Clone<CloneableClass> {
constructor(public a: number) {}

clone(this: Clone<CloneableClass>): CloneableClass;
clone(this: CloneableClass): CloneableClass;
clone(): CloneableClass {
return new CloneableClass(this.a);
}
}

const cloneable = new CloneableClass(1);
const x = some(1);
const y = some(cloneable);

expect(x.clone()).toStrictEqual(some(1));
expect(x.clone()).not.toBe(x); // Different reference
expect(x.clone().unwrap()).toBe(1);
expect(y.clone()).toStrictEqual(cloneable);
expect(y.clone()).not.toBe(cloneable);

combine

combine<U extends Option<unknown>[]>(...opts: U): Option<[T, ...SomeValues<U>]>

Combines this Option with other Option instances into a single Option containing a tuple of values.

The combine method takes an arbitrary number of Option instances, all sharing the same error-free structure. If all Option instances (including this one) are Some, it returns an Option with a tuple of their values in the order provided. If any Option is None, it returns None. The resulting tuple includes the value of this Option as the first element, followed by the values from the provided Option instances.

const a = some(Promise.resolve(1));
const b = some("hi");
const c = none<Date>();
const d = a.combine(b, c); // Option<[Promise<number>, string, Date]>

copy

copy(): Option<T>

Returns a shallow copy of the Option.

const value = { a: 1 };
const x = some(value);
const y = none<{ a: number }>();

expect(x.copy()).toStrictEqual(some({ a: 1 }));
expect(x.copy()).not.toBe(x); // Different option reference
expect(x.copy().unwrap()).toBe(value); // Same value reference
expect(y.copy()).toStrictEqual(none());

expect

expect(this: SettledOption<T>, msg?: string): T

Returns the value if Some, or throws an OptionError with msg (or a default message) if None.

note

Only available on Options that are Settled.

danger

This method throws if called on Option that is None.

const x = some(42);
const y = none<number>();

expect(x.expect("Missing value")).toBe(42);
expect(() => y.expect("Missing value")).toThrow("Missing value");
expect(() => y.expect()).toThrow("`expect`: called on `None`");

filter

filter(f: (x: T) => boolean): Option<T>

Returns the option if Some and f returns true, otherwise returns None.

info

If f throws, None is returned.

const x = some(2);
const y = none<number>();

expect(x.filter((n) => n > 0)).toStrictEqual(some(2));
expect(x.filter((n) => n < 0)).toStrictEqual(none());
expect(x.filter((_) => { throw new Error(); })).toStrictEqual(none());
expect(y.filter((n) => n > 0)).toStrictEqual(none());

flatten

flatten<U>(this: Option<Option<U>>): Option<U>

Flattens an Option of an Option into a single Option.

note

Only available on Options that hold another Option.

const x: Option<Option<Option<number>>> = some(some(some(6)));
const y: Option<Option<number>> = x.flatten();
const z = none<Option<Option<number>>>();

expect(x.flatten()).toStrictEqual(some(some(6)));
expect(y.flatten()).toStrictEqual(some(6));
expect(z.flatten()).toStrictEqual(none());

getOrInsert

getOrInsert(this: SettledOption<T>, x: T): T

Returns the contained value if Some, or inserts and returns x if None.

See also insert method, which updates the value even if the option already contains Some.

note
  • Only available on Options that are Settled.
  • This method mutates the Option.
const x = some(2);
const y = none<number>();

expect(x.getOrInsert(5)).toBe(2);
expect(y.getOrInsert(5)).toBe(5);
expect(y).toStrictEqual(some(5)); // y is mutated

getOrInsertWith

getOrInsertWith(this: SettledOption<T>, f: () => T): T

Returns the value if Some, or inserts and returns the result of f if None.

note
  • Only available on Options that are Settled.
  • Mutates this option to Some with f’s result if None. If f throws, the option remains unchanged.
danger

Throws OptionError if f throws.

const x = some(2);
const y = none<number>();
const z = none<number>();

expect(x.getOrInsertWith(() => 5)).toBe(2);
expect(y.getOrInsertWith(() => 5)).toBe(5);
expect(y).toStrictEqual(some(5)); // Mutated
expect(() => z.getOrInsertWith(() => { throw new Error(); }))
.toThrow("`getOrInsertWith`: callback `f` threw an exception");
expect(z).toStrictEqual(none()); // Unchanged

insert

insert(this: SettledOption<T>, x: T): T

Inserts x into the option and returns it, overwriting any existing value.

See also getOrInsert method, which doesn’t update the value if the option already contains Some.

note
  • Only available on Options that are Settled.
  • This method mutates the Option.
const x = some(2);
const y = none<number>();

expect(x.insert(5)).toBe(5);
expect(x).toStrictEqual(some(5));
expect(y.insert(5)).toBe(5);
expect(y).toStrictEqual(some(5));

inspect

inspect(f: (x: T) => unknown): Option<T>

Calls f with the value if Some, then returns a copy of this option.

note
  • Returns a new Option instance, not the original reference.
  • If f throws or returns a Promise that rejects, the error is ignored.
const x = some(2);
const y = none<number>();
let sideEffect = 0;

expect(x.inspect((n) => (sideEffect = n))).toStrictEqual(some(2));
expect(x.inspect((_) => { throw new Error(); })).toStrictEqual(some(2));
expect(sideEffect).toBe(2);
expect(y.inspect((n) => (sideEffect = n))).toStrictEqual(none());
expect(sideEffect).toBe(2); // Unchanged

isNone

isNone(): this is None<T>

Returns true if the option is None.

const x = some(2);
const y = none<number>();

expect(x.isNone()).toBe(false);
expect(y.isNone()).toBe(true);

isNoneOr

isNoneOr(f: (x: T) => boolean): boolean

Returns true if the option is None or if f returns true for the contained value.

note

If f throws, false is returned.

const x = some(2);
const y = none<number>();

expect(x.isNoneOr((n) => n > 0)).toBe(true);
expect(x.isNoneOr((_) => { throw new Error(); })).toBe(false);
expect(x.isNoneOr((n) => n < 0)).toBe(false);
expect(y.isNoneOr((n) => n > 0)).toBe(true);

isSome

isSome(): this is Some<T>

Returns true if the option is Some.

const x = some(2);
const y = none<number>();

expect(x.isSome()).toBe(true);
expect(y.isSome()).toBe(false);

isSomeAnd

isSomeAnd(f: (x: T) => boolean): this is Some<T> & boolean

Returns true if the option is Some and f returns true for the contained value.

note

If f throws, false is returned.

const x = some(2);
const y = none<number>();

expect(x.isSomeAnd((n) => n > 0)).toBe(true);
expect(x.isSomeAnd((_) => { throw new Error(); })).toBe(false);
expect(x.isSomeAnd((n) => n < 0)).toBe(false);
expect(y.isSomeAnd((n) => n > 0)).toBe(false);

iter

iter(): IterableIterator<T, T, void>

Returns an iterator over this option’s value, yielding it if Some or nothing if None.

note
  • Yields exactly one item for Some, or zero items for None.
  • Compatible with for...of loops and spread operators.
const x = some(42);
const y = none<number>();

const iterX = x.iter();
expect(iterX.next()).toEqual({ value: 42, done: false });
expect(iterX.next()).toEqual({ done: true });

const iterY = y.iter();
expect(iterY.next()).toEqual({ done: true });

expect([...x.iter()]).toEqual([42]);
expect([...y.iter()]).toEqual([]);

map

map<U>(f: (x: T) => Awaited<U>): Option<U>

Maps the contained value with f if Some, returning a new Option; otherwise, returns None.

note

If f throws, None is returned.

const x = some(2);
const y = none<number>();

expect(x.map((n) => n * 2)).toStrictEqual(some(4));
expect(x.map((_) => { throw new Error(); })).toStrictEqual(none());
expect(y.map((n) => n * 2)).toStrictEqual(none());

mapAll

Maps this option by applying a callback to its full state, executing the callback for both Some and None, returning a new Option or a PendingOption, depending on what kind of predicate function was provided (see method overloads for more details).

Unlike andThen, which only invokes the callback for Some, this method always calls f, passing the entire Option as its argument.

note

If f throws or returns a Promise that rejects, the error is silently ignored and None (or a PendingOption resolves to None) is returned.

const someOpt = some(42);
const noneOpt = none<number>();
const undefOpt = some(undefined);

expect(someOpt.mapAll((opt) => some(opt.unwrapOr(0) + 1))).toStrictEqual(some(43));
expect(noneOpt.mapAll((opt) => some(opt.unwrapOr(0) + 1))).toStrictEqual(some(1));
expect(undefOpt.mapAll((opt) => some(opt.isSome() ? "some" : "none"))).toStrictEqual(some("some"));

const mappedSome = someOpt.mapAll((opt) => Promise.resolve(some(opt.unwrapOr(0))));
expect(isPendingOption(mappedSome)).toBe(true);
expect(await mappedSome).toStrictEqual(some(42));

const mappedNone = noneOpt.mapAll((opt) => Promise.resolve(some(opt.unwrapOr(0) + 1)));
expect(isPendingOption(mappedNone)).toBe(true);
expect(await mappedNone).toStrictEqual(some(1));

mapOr

mapOr<U>(this: SettledOption<T>, def: Awaited<U>, f: (x: T) => Awaited<U>): U

Returns f applied to the value if Some, otherwise returns def.

note
  • Only available on Options that are Settled.
  • f has to return a synchronous (Awaited) value.
  • If f throws, returns def.
const x = some(2);
const y = none<number>();

expect(x.mapOr(0, (n) => n * 2)).toBe(4);
expect(x.mapOr(0, (_) => { throw new Error(); })).toBe(0);
expect(y.mapOr(0, (n) => n * 2)).toBe(0);

mapOrElse

mapOrElse<U>(this: SettledOption<T>, mkDef: () => Awaited<U>, f: (x: T) => Awaited<U>): U

Returns f applied to the contained value if Some, otherwise returns the result of mkDef.

note
  • Only available on Options that are Settled.
  • If f throws, the error is silently ignored and result of mkDef is returned.
danger

Throws OptionError if mkDef is called and throws an exception. Original error will be set as OptionError.reason.

const x = some(2);
const y = none<number>();

expect(x.mapOrElse(() => 0, n => n * 2)).toBe(4);
expect(x.mapOrElse(() => 1, _ => { throw new Error() })).toBe(1);
expect(() => x.mapOrElse(() => { throw new Error() }, _ => { throw new Error() })).toThrow(OptionError);
expect(y.mapOrElse(() => 0, n => n * 2)).toBe(0);

match

match<U, F = U>(this: SettledOption<T>, f: (x: T) => Awaited<U>, g: () => Awaited<F>): U | F

Matches the option, returning f applied to the value if Some, or g if None.

note
  • Only available on Options that are Settled.
  • If f or g returns a Promise that rejects, the caller is responsible for handling the rejection.
danger

Throws OptionError if f or g throws an exception. Original error will be set as OptionError.reason.

const x = some(2);
const y = none<number>();

expect(x.match(n => n * 2, () => 0)).toBe(4);
expect(() => x.match(_ => { throw new Error() }, () => 0)).toThrow(OptionError);
expect(y.match(n => n * 2, () => 0)).toBe(0);
expect(() => y.match(n => n * 2, () => { throw new Error() })).toThrow(OptionError);

okOr

okOr<E>(y: Awaited<E>): Result<T, E>

Converts to a Result, using y as the error value if this option is None. Some(v) is mapped to Ok(v) and None to Err(y).

const x = some(2);
const y = none<number>();

expect(x.okOr("error")).toStrictEqual(ok(2));
expect(y.okOr("error")).toStrictEqual(err("error"));

okOrElse

okOrElse<E>(mkErr: () => Awaited<E>): Result<T, E>

Converts to a Result, using the result of mkErr as the error value if None. Some(v) is mapped to Ok(v) and None to Err(mkErr()).

const x = some(2);
const y = none<number>();

expect(x.okOrElse(() => "error")).toStrictEqual(ok(2));
expect(y.okOrElse(() => "error")).toStrictEqual(err("error"));

or

or(x: Option<T>): Option<T>

Returns the current option if it is Some, otherwise returns x.

const x = some(2);
const y = none<number>();

expect(x.or(some(3))).toStrictEqual(some(2));
expect(x.or(none())).toStrictEqual(some(2));
expect(y.or(some(3))).toStrictEqual(some(3));
expect(y.or(none())).toStrictEqual(none());

orElse

orElse(f: () => Option<T>): Option<T>

Returns the current option if Some, otherwise returns the result of f.

note

If f throws, None is returned.

const x = some(2);
const y = none<number>();

expect(x.orElse(() => some(3))).toStrictEqual(some(2));
expect(y.orElse(() => some(3))).toStrictEqual(some(3));
expect(y.orElse(() => { throw new Error(); })).toStrictEqual(none());
expect(y.orElse(() => none())).toStrictEqual(none());

replace

replace(x: T): Option<T>

Replaces the current value with x and returns the old Option.

note

This method mutates the Option.

const x = some(2);
const y = none<number>();

expect(x.replace(5)).toStrictEqual(some(2));
expect(x).toStrictEqual(some(5));
expect(y.replace(5)).toStrictEqual(none());
expect(y).toStrictEqual(some(5)); // y is mutated

take

take(): Option<T>

Takes the value out of the Option, leaving None in its place.

note

This method mutates the Option.

const x = some(2);
const y = none<number>();

expect(x.take()).toStrictEqual(some(2));
expect(x).toStrictEqual(none());
expect(y.take()).toStrictEqual(none());
expect(y).toStrictEqual(none());

takeIf

takeIf(f: (x: T) => boolean): Option<T>

Takes the value out of the Option, but only if f returns true. Similar to take, but conditional.

note
  • This method mutates the Option.
  • If f throws, None is returned and the original value remains unchanged.
const x = some(2);
const y = none<number>();
const z = some(1);

expect(x.takeIf((n) => n > 0)).toStrictEqual(some(2));
expect(x).toStrictEqual(none());
expect(x.takeIf((n) => n < 0)).toStrictEqual(none());
expect(y.takeIf((n) => n > 0)).toStrictEqual(none());
expect(z.takeIf((_) => { throw new Error(); })).toStrictEqual(none());
expect(z).toStrictEqual(some(1));

tap

tap(f: (x: Option<T>) => unknown): Option<T>

Executes f with a copy of this Option, then returns a new copy unchanged.

Useful for side-effects like logging, works with both Some and None.

note
  • If f throws or rejects, the error is ignored.
  • If f returns a promise, the promise is not awaited before returning.
const x = some(42);
const y = none<number>();
let log = "";

expect(x.tap((opt) => (log = opt.toString()))).toStrictEqual(some(42));
expect(log).toBe("Some { 42 }");
expect(y.tap((opt) => (log = opt.toString()))).toStrictEqual(none());
expect(log).toBe("None");

toPending

toPending(): PendingOption<Awaited<T>>

Maps the option to a PendingOption by supplying a shallow copy of the option to a PendingOption factory.

Useful for transposing an option with PromiseLike value to a PendingOption with Awaited value.

note

If inner T is a promise-like that rejects, maps to a PendingOption with None.

const value = { a: 1 };
const x = some(value);
const y = none<number>();
const pendingX = x.toPending();

expect(isPendingOption(pendingX)).toBe(true);
expect(await pendingX).toStrictEqual(some({ a: 1 }));
value.a = 2;
expect(await pendingX).toStrictEqual(some({ a: 2 }));
expect(await y.toPending()).toStrictEqual(none());

toPendingCloned

toPendingCloned(this: Option<Cloneable<T>>): PendingOption<Awaited<T>>

Maps this option to a PendingOption by supplying a clone of the option to PendingOption factory.

Useful for transposing an option with PromiseLike value to a PendingOption with Awaited value.

note

If inner T is a promise-like that rejects, maps to a PendingOption with None.

class CloneableClass implements Clone<CloneableClass> {
constructor(public a: number) {}

clone(this: Clone<CloneableClass>): CloneableClass;
clone(this: CloneableClass): CloneableClass;
clone(): CloneableClass {
return new CloneableClass(this.a);
}
}

const value = new CloneableClass(0);
const x = some(value);
const y = none<number>();
const pendingX = x.toPendingCloned();

expect(isPendingOption(pendingX)).toBe(true);
expect((await pendingX).unwrap().a).toBe(0);
value.a = 42;
expect((await pendingX).unwrap().a).toBe(0);
expect(await y.toPendingCloned()).toStrictEqual(none());

toString

toString(): string

Returns a string representation of the Option.

const x = some(2);
const y = none<number>();

expect(x.toString()).toBe("Some { 2 }");
expect(y.toString()).toBe("None");

transpose

transpose<U, E>(this: Option<Result<U, E>>): Result<Option<U>, E>

Transposes an Option of a Result into a Result of an Option.

Maps None to Ok(None), Some(Ok(_)) to Ok(Some(_)), and Some(Err(_)) to Err(_).

note

Only available on Options that hold a Result value.

const x = none<Result<number, string>>();
const y = some<Result<number, string>>(ok(2));
const z = some<Result<number, string>>(err("error"));

expect(x.transpose()).toStrictEqual(ok(none()));
expect(y.transpose()).toStrictEqual(ok(some(2)));
expect(z.transpose()).toStrictEqual(err("error"));

unwrap

unwrap(this: SettledOption<T>): T

Returns the value if Some, or throws an OptionError if None.

note

Only available on Options that are Settled.

danger

Throws OptionError if this is None

const x = some(2);
const y = none<number>();

expect(x.unwrap()).toBe(2);
expect(() => y.unwrap()).toThrow("`unwrap`: called on `None`");

unwrapOr

unwrapOr(this: SettledOption<T>, def: Awaited<T>): T

Returns the contained value if Some, or def if None.

note

Only available on Options that are Settled.

const x = some(2);
const y = none<number>();

expect(x.unwrapOr(0)).toBe(2);
expect(y.unwrapOr(0)).toBe(0);

unwrapOrElse

unwrapOrElse(this: SettledOption<T>, mkDef: () => Awaited<T>): T

Returns the contained value if Some, or the result of mkDef if None.

note

Only available on Options that are Settled.

danger

Throws OptionError if mkDef throws. Original error will be set as OptionError.reason.

const x = some(2);
const y = none<number>();

expect(x.unwrapOrElse(() => 0)).toBe(2);
expect(y.unwrapOrElse(() => 0)).toBe(0);
expect(() => y.unwrapOrElse(() => { throw new Error(); })).toThrow(OptionError);

xor

Returns Some (or PendingOption with Some, when y is a promise) if exactly one of this or y is Some, otherwise returns None.

const x = some(2);
const y = none<number>();

expect(x.xor(some(3))).toStrictEqual(none());
expect(x.xor(none())).toStrictEqual(some(2));
expect(y.xor(some(3))).toStrictEqual(some(3));
expect(y.xor(none())).toStrictEqual(none());

expect(isPendingOption(x.xor(Promise.resolve(some(3))))).toBe(true);
expect(await x.xor(Promise.resolve(some(3)))).toStrictEqual(none());
expect(await x.xor(Promise.resolve(none()))).toStrictEqual(some(2));
expect(await y.xor(Promise.resolve(some(3)))).toStrictEqual(some(3));