Created
January 5, 2022 11:52
-
-
Save mskoroglu/bc63e7edf039439f6ae2f51de7d89cd8 to your computer and use it in GitHub Desktop.
java.util.Optional implementation in TypeScript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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