From LACampbell, 1 Year ago, written in TypoScript.
  1. type MapFunction<L, R, T> = Readonly<{
  2.         left: (l: L) => T,
  3.         right: (r: R) => T
  4. }>
  5.  
  6. export module EIther {
  7.         export type N = Number
  8. }
  9.  
  10. export default abstract class Either<L, R> {
  11.         abstract map<T>(f: MapFunction<L, R, T>): T
  12.  
  13.         abstract leftMap<L2>(f: (l: L) => L2): Either<L2, R>
  14.         abstract rightMap<R2>(f: (r: R) => R2): Either<L, R2>
  15.  
  16.         abstract leftMapThen<L2>(f: (l: L) => Promise<L2>): Promise<Either<L2, R>>
  17.                
  18.         abstract rightMapThen<R2>(f: (r: R) => Promise<R2>): Promise<Either<L, R2>>
  19.        
  20.         abstract leftFlatMap<L2>(f: (l: L) => Either<L2, R>): Either<L2, R>
  21.         abstract rightFlatMap<R2>(f: (r: R) => Either<L, R2>): Either<L, R2>
  22.  
  23.         abstract leftOrElse(f: (r: R) => L): L
  24.         abstract rightOrElse(f: (l: L) => R): R
  25.  
  26.         abstract toUnion(): L | R
  27.  
  28.         abstract isRight(): boolean
  29.  
  30.         static left<L, R>(left: L) : Either<L, R> {
  31.                 return new Left<L, R>(left)
  32.         }
  33.        
  34.         static right<L, R>(right: R) : Either<L, R> {
  35.                 return new Right<L, R>(right)
  36.         }
  37.        
  38.         static fromBoolean<L, R>(isRight: boolean, l: L, r: R) {
  39.                 return isRight ? Either.right<L, R>(r) : Either.left<L, R>(l)
  40.         }
  41.  
  42.         static fromDynamic<R>(f: () => R): Either<TypeError, R> {
  43.                 try {
  44.                         return Either.right(f())
  45.                 } catch (e) {
  46.                         if (e instanceof TypeError) {
  47.                                 return Either.left(e)
  48.                         } else {
  49.                                 throw e
  50.                         }
  51.                 }
  52.         }
  53.  
  54.         static async fromDynamicAsync<R>(
  55.                 f: () => Promise<R>
  56.         ): Promise<Either<TypeError, R>> {
  57.                 return Either.fromDynamic(f).rightMapThen(r => r)
  58.         }
  59. }
  60.  
  61. class Left<L, R> implements Either<L, R> {
  62.         constructor(private readonly data: L) { }
  63.  
  64.         map<T>(f: MapFunction<L, R, T>) {              
  65.                 return f.left(this.data)
  66.         }
  67.  
  68.         leftMap<T>(f: (l: L) => T): Either<T, R> {
  69.                 return new Left(f(this.data))
  70.         }
  71.  
  72.         rightMap<R2>(_: (r: R) => R2): Either<L, R2>{
  73.                 return new Left(this.data)
  74.         }
  75.  
  76.         async leftMapThen<L2>(f: (l: L) => Promise<L2>): Promise<Either<L2, R>> {
  77.                 return new Left(await f(this.data))
  78.         }
  79.        
  80.         async rightMapThen<R2>(_: (r: R) => Promise<R2>): Promise<Either<L, R2>> {
  81.                 return Promise.resolve(new Left<L, R2>(this.data))
  82.         }
  83.  
  84.         leftFlatMap<L2>(f: (l: L) => Either<L2, R>): Either<L2, R> {
  85.                 return f(this.data)    
  86.         }
  87.  
  88.         rightFlatMap<R2>(_: (r: R) => Either<L, R2>): Either<L, R2> {
  89.                 return new Left<L, R2>(this.data)
  90.         }
  91.  
  92.         leftOrElse(f: (r: R) => L): L {
  93.                 return this.data
  94.         }
  95.        
  96.         rightOrElse(f: (l: L) => R): R {
  97.                 return f(this.data)
  98.         }
  99.  
  100.         toUnion() {
  101.                 return this.data;
  102.         }
  103.  
  104.         isRight() { return false; }
  105. }
  106.  
  107. class Right<L, R> implements Either<L, R> {
  108.         constructor(private readonly data: R) { }
  109.  
  110.         map<T>(f: MapFunction<L, R, T>) {
  111.                 return f.right(this.data)
  112.         }
  113.  
  114.         leftMap<L2>(_: (l: L) => L2): Either<L2, R> {
  115.                 return new Right(this.data)            
  116.         }
  117.  
  118.         rightMap<R2>(f: (r: R) => R2): Either<L, R2>{
  119.                 return new Right(f(this.data))
  120.         }
  121.  
  122.         async leftMapThen<L2>(_: (l: L) => Promise<L2>): Promise<Either<L2, R>> {
  123.                 return Promise.resolve(new Right<L2, R>(this.data))
  124.         }
  125.        
  126.         async rightMapThen<R2>(f: (r: R) => Promise<R2>): Promise<Either<L, R2>> {
  127.                 return new Right(await f(this.data))
  128.         }
  129.  
  130.         leftFlatMap<L2>(_: (l: L) => Either<L2, R>): Either<L2, R> {           
  131.                 return new Right<L2, R>(this.data)
  132.         }
  133.  
  134.         rightFlatMap<R2>(f: (r: R) => Either<L, R2>): Either<L, R2> {
  135.                 return f(this.data)
  136.         }
  137.  
  138.         leftOrElse(f: (r: R) => L): L {
  139.                 return f(this.data)
  140.         }
  141.        
  142.         rightOrElse(_: (l: L) => R): R {
  143.                 return this.data               
  144.         }
  145.  
  146.         toUnion() {
  147.                 return this.data;
  148.         }
  149.  
  150.         isRight() { return true; }
  151. }
captcha