diff options
Diffstat (limited to 'u/fn/either.ts')
-rw-r--r-- | u/fn/either.ts | 180 |
1 files changed, 83 insertions, 97 deletions
diff --git a/u/fn/either.ts b/u/fn/either.ts index ffe8033..8c47b64 100644 --- a/u/fn/either.ts +++ b/u/fn/either.ts @@ -1,114 +1,100 @@ -import { type Mapper, type Supplier, isObject } from "@emprespresso/pengueno"; +import { type Mapper, type Supplier, isObject } from '@emprespresso/pengueno'; -type IEitherTag = "IEither"; -const iEitherTag: IEitherTag = "IEither"; +type IEitherTag = 'IEither'; +const iEitherTag: IEitherTag = 'IEither'; export interface _Either<LeftT, RightT, T> { - readonly isLeft: LeftT; - readonly isRight: RightT; - readonly value: T; + readonly isLeft: LeftT; + readonly isRight: RightT; + readonly value: T; } export type Left<E> = _Either<true, false, E>; export type Right<T> = _Either<false, true, T>; export interface IEither<E, T> { - readonly _tag: IEitherTag; - - mapBoth: <_E, _T>( - errBranch: Mapper<E, _E>, - okBranch: Mapper<T, _T>, - ) => IEither<_E, _T>; - fold: <_T>(folder: Mapper<Left<E> | Right<T>, _T>) => _T; - moveRight: <_T>(t: _T) => IEither<E, _T>; - mapRight: <_T>(mapper: Mapper<T, _T>) => IEither<E, _T>; - mapLeft: <_E>(mapper: Mapper<E, _E>) => IEither<_E, T>; - flatMap: <_T>(mapper: Mapper<T, IEither<E, _T>>) => IEither<E, _T>; - flatMapAsync: <_T>( - mapper: Mapper<T, Promise<IEither<E, _T>>>, - ) => Promise<IEither<E, _T>>; + readonly _tag: IEitherTag; + + mapBoth: <_E, _T>(errBranch: Mapper<E, _E>, okBranch: Mapper<T, _T>) => IEither<_E, _T>; + fold: <_T>(folder: Mapper<Left<E> | Right<T>, _T>) => _T; + moveRight: <_T>(t: _T) => IEither<E, _T>; + mapRight: <_T>(mapper: Mapper<T, _T>) => IEither<E, _T>; + mapLeft: <_E>(mapper: Mapper<E, _E>) => IEither<_E, T>; + flatMap: <_T>(mapper: Mapper<T, IEither<E, _T>>) => IEither<E, _T>; + flatMapAsync: <_T>(mapper: Mapper<T, Promise<IEither<E, _T>>>) => Promise<IEither<E, _T>>; } export class Either<E, T> implements IEither<E, T> { - private readonly self: Left<E> | Right<T>; - - private constructor( - init: { err?: E; ok?: T }, - public readonly _tag: IEitherTag = iEitherTag, - ) { - this.self = <Left<E> | Right<T>>{ - isLeft: "err" in init, - isRight: "ok" in init, - value: init.err ?? init.ok!, - }; - } - - public moveRight<_T>(t: _T) { - return this.mapRight(() => t); - } - - public fold<_T>(folder: Mapper<Left<E> | Right<T>, _T>): _T { - return folder(this.self); - } - - public mapBoth<_E, _T>( - errBranch: Mapper<E, _E>, - okBranch: Mapper<T, _T>, - ): IEither<_E, _T> { - if (this.self.isLeft) return Either.left(errBranch(this.self.value)); - return Either.right(okBranch(this.self.value)); - } - - public flatMap<_T>(mapper: Mapper<T, IEither<E, _T>>): IEither<E, _T> { - if (this.self.isRight) return mapper(this.self.value); - return Either.left<E, _T>(this.self.value); - } - - public mapRight<_T>(mapper: Mapper<T, _T>): IEither<E, _T> { - if (this.self.isRight) return Either.right<E, _T>(mapper(this.self.value)); - return Either.left<E, _T>(this.self.value); - } - - public mapLeft<_E>(mapper: Mapper<E, _E>): IEither<_E, T> { - if (this.self.isLeft) return Either.left<_E, T>(mapper(this.self.value)); - return Either.right<_E, T>(this.self.value); - } - - public async flatMapAsync<_T>( - mapper: Mapper<T, Promise<IEither<E, _T>>>, - ): Promise<IEither<E, _T>> { - if (this.self.isLeft) { - return Promise.resolve(Either.left<E, _T>(this.self.value)); + private readonly self: Left<E> | Right<T>; + + private constructor( + init: { err?: E; ok?: T }, + public readonly _tag: IEitherTag = iEitherTag, + ) { + this.self = <Left<E> | Right<T>>{ + isLeft: 'err' in init, + isRight: 'ok' in init, + value: init.err ?? init.ok!, + }; } - return await mapper(this.self.value).catch((err) => - Either.left<E, _T>(err), - ); - } - - static left<E, T>(e: E): IEither<E, T> { - return new Either<E, T>({ err: e }); - } - - static right<E, T>(t: T): IEither<E, T> { - return new Either<E, T>({ ok: t }); - } - - static fromFailable<E, T>(s: Supplier<T>): IEither<E, T> { - try { - return Either.right<E, T>(s()); - } catch (e) { - return Either.left<E, T>(e as E); + + public moveRight<_T>(t: _T) { + return this.mapRight(() => t); + } + + public fold<_T>(folder: Mapper<Left<E> | Right<T>, _T>): _T { + return folder(this.self); + } + + public mapBoth<_E, _T>(errBranch: Mapper<E, _E>, okBranch: Mapper<T, _T>): IEither<_E, _T> { + if (this.self.isLeft) return Either.left(errBranch(this.self.value)); + return Either.right(okBranch(this.self.value)); + } + + public flatMap<_T>(mapper: Mapper<T, IEither<E, _T>>): IEither<E, _T> { + if (this.self.isRight) return mapper(this.self.value); + return Either.left<E, _T>(this.self.value); + } + + public mapRight<_T>(mapper: Mapper<T, _T>): IEither<E, _T> { + if (this.self.isRight) return Either.right<E, _T>(mapper(this.self.value)); + return Either.left<E, _T>(this.self.value); + } + + public mapLeft<_E>(mapper: Mapper<E, _E>): IEither<_E, T> { + if (this.self.isLeft) return Either.left<_E, T>(mapper(this.self.value)); + return Either.right<_E, T>(this.self.value); + } + + public async flatMapAsync<_T>(mapper: Mapper<T, Promise<IEither<E, _T>>>): Promise<IEither<E, _T>> { + if (this.self.isLeft) { + return Promise.resolve(Either.left<E, _T>(this.self.value)); + } + return await mapper(this.self.value).catch((err) => Either.left<E, _T>(err)); + } + + static left<E, T>(e: E): IEither<E, T> { + return new Either<E, T>({ err: e }); + } + + static right<E, T>(t: T): IEither<E, T> { + return new Either<E, T>({ ok: t }); + } + + static fromFailable<E, T>(s: Supplier<T>): IEither<E, T> { + try { + return Either.right<E, T>(s()); + } catch (e) { + return Either.left<E, T>(e as E); + } + } + + static async fromFailableAsync<E, T>(s: Supplier<Promise<T>> | Promise<T>): Promise<IEither<E, T>> { + return await (typeof s === 'function' ? s() : s) + .then((t: T) => Either.right<E, T>(t)) + .catch((e: E) => Either.left<E, T>(e)); } - } - - static async fromFailableAsync<E, T>( - s: Supplier<Promise<T>>, - ): Promise<IEither<E, T>> { - return await s() - .then((t: T) => Either.right<E, T>(t)) - .catch((e: E) => Either.left<E, T>(e)); - } } export const isEither = <E, T>(o: unknown): o is IEither<E, T> => { - return isObject(o) && "_tag" in o && o._tag === "IEither"; + return isObject(o) && '_tag' in o && o._tag === 'IEither'; }; |