Skip to content

Instantly share code, notes, and snippets.

@lilBunnyRabbit
Last active November 28, 2024 08:37
Show Gist options
  • Save lilBunnyRabbit/ab44b9bafca79cf1fa8024d833a60e24 to your computer and use it in GitHub Desktop.
Save lilBunnyRabbit/ab44b9bafca79cf1fa8024d833a60e24 to your computer and use it in GitHub Desktop.
TypeScript implementation of Java Optional

Important

The Optional implementation previously available in this gist has been officially integrated into the @lilbunnyrabbit/optional package. For continued support and access to the latest features, please refer to the package.

Definition A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value. Additional methods that depend on the presence or absence of a contained value are provided, such as orElse() (return a default value if value not present) and ifPresent() (execute a block of code if the value is present).

This is a value-based class; use of identity-sensitive operations (including reference equality (==), identity hash code, or synchronization) on instances of Optional may have unpredictable results and should be avoided.

The main difference is that it doesn't throw errors if the value is not defined and simply just returns null.

API

public static <T> Optional<T> of(T value)

const optional: Optional<number> = Optional(123);
const optionalString: Optional<string> = Optional("123" as string | undefined | null);
const optionalNull: OptionalEmpty = Optional(null);
const optionalUndefined: OptionalEmpty = Optional(undefined);

public T get()

const value: number | null = optional.get();

public boolean isPresent()

if (optional.isPresent()) {
  const copy: OptionalPresent<number> = optional;
  const value: number = optional.get();
} else {
  const copy: OptionalEmpty = optional;
  const value: null = optional.get();
}

Opposite of public boolean isPresent()

if (optional.isEmpty()) {
  const copy: OptionalEmpty = optional;
  const value: null = optional.get();
} else {
  const copy: OptionalPresent<number> = optional;
  const value: number = optional.get();
}

public void ifPresent(Consumer<? super T> consumer)

optional.ifPresent((value) => console.log("Present:", value));

Opposite of public void ifPresent(Consumer<? super T> consumer)

optional.ifEmpty(() => console.log("Empty"));

public Optional<T> filter(Predicate<? super T> predicate)

const filtered: Optional<number> = optional.filter((value) => value > 3);

public <U> Optional<U> map(Function<? super T,? extends U> mapper)

const mapped: Optional<string> = optional.map((value) => String(value));

public <U> Optional<U> flatMap(Function<? super T,Optional<U>> mapper)

const flatMapped: Optional<string> = optional.flatMap((value) => Optional(String(value)));

public T orElse(T other)

const orElse: number = optional.orElse(123);

public T orElseGet(Supplier<? extends T> other)

const orElseGet: number = optional.orElseGet(() => 123);

public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X extends Throwable

try {
  const value: number = optional.orElseThrow(() => new Error("Value not present"));
} catch (error) {
  console.error(error);
}
/**
* TypeScript implementation of {@link https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html java.util.Optional<T>}.
*
* A container object which may or may not contain a non-null value.
*
* @template T - the type of the value
*/
class OptionalValue<T> {
/**
* Creates an instance of `OptionalValue`.
* @param value - the type of the value
*/
protected constructor(private value: T) {}
/**
* Returns true if there is a value present, otherwise false.
*/
static isPresent<T>(value: T): value is NonNullable<T> {
return value !== undefined && value !== null;
}
/**
* Returns an empty `OptionalValue` instance. No value is present for this `OptionalValue`.
*/
static empty(): OptionalEmpty {
return new OptionalValue(null);
}
/**
* Returns an `OptionalValue` describing the specified value, if non-null,
* otherwise returns an empty `OptionalValue`.
*
* @template T - the type of the value
* @param value - the possibly-null value to describe
*/
static of<T>(value: T): Optional<NonNullable<T>> {
if (OptionalValue.isPresent(value)) {
return new OptionalValue(value);
}
return OptionalValue.empty();
}
/**
* Returns value held by this `OptionalValue`.
*/
public get(): T {
return this.value;
}
/**
* Returns true if there is a value present, otherwise false.
*/
public isPresent(): this is OptionalPresent<T> {
return OptionalValue.isPresent(this.value);
}
/**
* If a value is present, invoke the specified consumer with the value, otherwise do nothing.
*
* @param consumer - callback to be executed if a value is present
*/
public ifPresent(consumer: (value: NonNullable<T>) => void): this {
if (this.isPresent()) {
consumer(this.value);
}
return this;
}
/**
* Returns true if there is a no value present, otherwise false.
*/
public isEmpty(): this is OptionalEmpty {
return !OptionalValue.isPresent(this.value);
}
/**
* If a value is not present, invoke the specified consumer, otherwise do nothing.
*
* @param consumer - callback to be executed if a value is not present
*/
public ifEmpty(consumer: () => void): this {
if (this.isEmpty()) {
consumer();
}
return this;
}
/**
* If a value is present, and the value matches the given predicate,
* return an `OptionalValue` describing the value, otherwise return an empty `OptionalValue`.
*
* @template U - the type of the value
* @param predicate - a predicate to apply to the value, if present
*/
public filter<U>(this: Optional<U>, predicate: (value: NonNullable<U>) => boolean): Optional<U> {
if (this.isEmpty()) {
return this;
}
if (predicate(this.value)) {
return this;
}
return OptionalValue.empty();
}
/**
* If a value is present, apply the provided mapping function to it, and if the result is non-null,
* return an `OptionalValue` describing the result. Otherwise return an empty `OptionalValue`.
*
* @template U - the type of the value
* @template V - the type of the result of the mapping function
* @param mapper - a mapping function to apply to the value, if present
*/
public map<U, V>(this: Optional<U>, mapper: (value: NonNullable<U>) => V): Optional<V> {
if (this.isEmpty()) {
return this;
}
const mapped = mapper(this.value);
if (OptionalValue.isPresent(mapped)) {
return OptionalValue.of(mapped);
}
return OptionalValue.empty();
}
/**
* If a value is present, apply the provided `OptionalValue`-bearing mapping function to it,
* return that result, otherwise return an empty `OptionalValue`.
* This method is similar to `map` method, but the provided mapper is one whose result is already an `OptionalValue`,
* and if invoked, `flatMap` does not wrap it with an additional `OptionalValue`.
*
* @template U - the type of the value
* @template V - the type parameter to the `OptionalValue` returned by
* @param mapper - a mapping function to apply to the value, if present the mapping function
*/
public flatMap<U, V>(this: Optional<U>, mapper: (value: NonNullable<U>) => Optional<V>): Optional<V> {
if (this.isEmpty()) {
return this;
}
return mapper(this.value);
}
/**
* Returns the value if present, otherwise return other.
*
* @template U - the type of the value
* @param other - the value to be returned if there is no value present
*/
public orElse<U>(this: Optional<U>, other: NonNullable<U>): NonNullable<U> {
if (this.isPresent()) {
return this.value;
}
return other;
}
/**
* Returns the value if present, otherwise invokes other and returns the result of that invocation.
*
* @template U - the type of the value
* @param other - a callback whose result is returned if no value is present
*/
public orElseGet<U>(this: Optional<U>, other: () => NonNullable<U>): NonNullable<U> {
if (this.isPresent()) {
return this.value;
}
return other();
}
/**
* Returns the contained value, if present, otherwise throws an `Error` created by the provided supplier.
*
* @template E - type of the `Error` to be thrown
* @param errorSupplier - the supplier which will return the `Error` to be thrown
*/
public orElseThrow<E extends Error>(errorSupplier: () => E): NonNullable<T> {
if (this.isPresent()) {
return this.value;
}
throw errorSupplier();
}
}
/**
* Type of empty `OptionalValue` instance.
*/
export type OptionalEmpty = OptionalValue<null>;
/**
* Type of present `OptionalValue` instance.
*/
export type OptionalPresent<T> = OptionalValue<NonNullable<T>>;
/**
* TypeScript implementation of {@link https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html java.util.Optional<T>}.
*
* A container object which may or may not contain a non-null value.
*
* @template T - the type of the value
*/
export type Optional<T> = OptionalEmpty | OptionalPresent<T>;
/**
* Optional function definition.
*/
interface OptionalFunction {
/**
* Returns an `OptionalValue` describing the specified value, if non-null,
* otherwise returns an empty `OptionalValue`.
*
* @template T - the type of the value
* @param value - the possibly-null value to describe
*/
<T>(value: T): Optional<NonNullable<T>>;
/**
* Returns an empty `OptionalValue` instance. No value is present for this `OptionalValue`.
*/
empty(): OptionalEmpty;
}
export const Optional = OptionalValue.of as OptionalFunction;
Optional.empty = OptionalValue.empty;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment