Skip to content

Instantly share code, notes, and snippets.

@mskoroglu
Created January 5, 2022 11:52
Show Gist options
  • Save mskoroglu/bc63e7edf039439f6ae2f51de7d89cd8 to your computer and use it in GitHub Desktop.
Save mskoroglu/bc63e7edf039439f6ae2f51de7d89cd8 to your computer and use it in GitHub Desktop.
java.util.Optional implementation in TypeScript
export default class Optional<T> {
private static readonly EMPTY = new Optional(null);
private readonly value: T | null;
private constructor(value: T | null) {
this.value = value;
}
public static empty<T>(): Optional<T> {
return this.EMPTY as unknown as Optional<T>;
}
public static of<T>(value: T): Optional<T> {
return new Optional(value);
}
public static ofNullable<T>(value: T | null): Optional<T> {
return value === null ? this.empty() : this.of(value);
}
public get(): T {
if (this.value === null) {
throw new Error("No value present");
}
return this.value;
}
public isPresent(): boolean {
return !this.isEmpty();
}
public isEmpty(): boolean {
return this.value === null;
}
public ifPresent(action: (value: T) => void): void {
if (this.isPresent()) {
action(this.value!);
}
}
public ifPresentOrElse(
action: (value: T) => void,
emptyAction: () => void
): void {
if (this.isPresent()) {
action(this.value!);
} else {
emptyAction();
}
}
public filter(predicate: (value: T) => boolean): Optional<T> {
if (this.isEmpty()) {
return this;
} else {
return predicate(this.value!) ? this : Optional.empty();
}
}
public map<U>(mapper: (value: T) => U): Optional<U> {
if (this.isEmpty()) {
return Optional.empty();
} else {
return Optional.ofNullable<U>(mapper(this.value!)) as Optional<U>;
}
}
public flatMap<U>(mapper: (value: T) => Optional<U>): Optional<U> {
if (this.isEmpty()) {
return Optional.empty();
} else {
return mapper(this.value!);
}
}
public or(supplier: () => Optional<T>): Optional<T> {
if (this.isPresent()) {
return this;
} else {
return supplier();
}
}
public orElse(other: T): T {
if (this.isPresent()) {
return this.value!;
} else {
return other;
}
}
public orElseGet(supplier: () => T): T {
if (this.isPresent()) {
return this.value!;
} else {
return supplier();
}
}
public orElseThrow(
errorSupplier: () => Error = () => new Error("No value present")
): T {
if (this.isEmpty()) {
throw errorSupplier();
}
return this.value!;
}
public equals(obj: any): boolean {
if (this === obj) {
return true;
}
if (!(obj instanceof Optional)) {
return false;
}
const other = obj as Optional<any>;
return this.value == other.value;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment