UNPKG

@dancrumb/fpish

Version:

FP-friendly classes for Typescript

131 lines (130 loc) 3.51 kB
import { Optional } from './Optional.js'; /** * The `Either<R,L>` type represents 2 possible values of 2 possible types. * * A common use case it to use this to represent the outcome of a function that could * be an error or a value: `const result: Either<ErrorType, ValueType>`. Convention has * `ErrorType` as the left-value and `ValueType` as the right-value. * * The type will only ever be single-valued, but it will always be single-valued */ export class Either { /** * Create a Left-valued `Either` * @param value */ static left(value) { return new Either(Optional.of(value), Optional.empty()); } /** * Create a Right-valued `Either` * @param value */ static right(value) { return new Either(Optional.empty(), Optional.of(value)); } left; right; constructor(l, r) { this.left = l; this.right = r; } /** * Returns whether or not the value is left-valued */ isLeft() { return this.left.isPresent(); } /** * Gets the left-value of the object. * * This will result in an error, if the object is not left-valued * * @throws {NoSuchElementException} */ getLeft() { return this.left.get(); } /** * Returns whether or not the value is right-valued */ isRight() { return this.right.isPresent(); } /** * Gets the right-value of the object. * * This will result in an error, if the object is not right-valued * * @throws {NoSuchElementException} */ getRight() { return this.right.get(); } map(lFunc, rFunc) { return this.left.map(lFunc).orElseGet(() => this.right.map(rFunc).get()); } mapLeft(lFunc) { return new Either(this.left.map(lFunc), this.right); } mapRight(rFunc) { return new Either(this.left, this.right.map(rFunc)); } proceedLeft(lFunc) { if (this.left.isPresent()) { return lFunc(this.left.get()); } return Either.right(this.right.get()); } proceedRight(rFunc) { if (this.right.isPresent()) { return rFunc(this.right.get()); } return Either.left(this.left.get()); } /** * Collapses an `Either` that may contain a left-value that is an `Either` * @param either */ static joinLeft(either) { if (either.isLeft()) { return either.getLeft(); } return Either.right(either.getRight()); } /** * Collapses an `Either` that may contain a right-value that is an `Either` * @param either */ static joinRight(either) { if (either.isRight()) { return either.getRight(); } return Either.left(either.getLeft()); } /** * Applies a function to the internal value. Since this returns void and takes functions that return * void, this relies entirely on side-effects.. * @param lFunc * @param rFunc */ apply(lFunc, rFunc) { this.left.ifPresent(lFunc); this.right.ifPresent(rFunc); return this; } /** * Runs the provided function if the left value is populated */ ifLeft(lFunc) { this.left.ifPresent(lFunc); return this; } /** * Runs the provided function if the right value is populated */ ifRight(rFunc) { this.right.ifPresent(rFunc); return this; } }