A social knowledge tool for researchers built on ATProto
at development 144 lines 3.5 kB view raw
1// Base Result types using discriminated union 2 3/** 4 * Represents a successful operation outcome. 5 * Contains the successful value of type T. 6 * E represents the potential error type for compatibility in the Result union. 7 */ 8export class Ok<T, E> { 9 public readonly value: T; 10 11 constructor(value: T) { 12 this.value = value; 13 } 14 15 /** Type guard indicating success */ 16 public isOk(): this is Ok<T, E> { 17 return true; 18 } 19 20 /** Type guard indicating failure */ 21 public isErr(): this is Err<T, E> { 22 return false; 23 } 24 25 public unwrap(): T { 26 return this.value; 27 } 28} 29 30/** 31 * Represents a failed operation outcome. 32 * Contains the error value of type E. 33 * T represents the potential success type for compatibility in the Result union. 34 */ 35export class Err<T, E> { 36 public readonly error: E; 37 38 constructor(error: E) { 39 this.error = error; 40 } 41 42 /** Type guard indicating success */ 43 public isOk(): this is Ok<T, E> { 44 return false; 45 } 46 47 /** Type guard indicating failure */ 48 public isErr(): this is Err<T, E> { 49 return true; 50 } 51 52 public unwrap(): T { 53 throw this.error; 54 } 55} 56 57/** 58 * Represents the outcome of an operation that can either succeed (Ok) or fail (Err). 59 * @template T The type of the value in case of success. 60 * @template E The type of the error in case of failure. Defaults to `Error`. 61 */ 62export type Result<T, E = Error> = Ok<T, E> | Err<T, E>; 63 64// Static factory functions 65 66/** 67 * Creates an Ok result containing the success value. 68 * @param value The success value. 69 */ 70export const ok = <T, E>(value: T): Ok<T, E> => new Ok(value); 71 72/** 73 * Creates an Err result containing the error value. 74 * @param error The error value. 75 */ 76export const err = <T, E>(error: E): Err<T, E> => new Err(error); 77 78/** 79 * Combines multiple Result instances. If all are Ok, returns an Ok result with an array of values. 80 * If any Result is an Err, returns the first Err encountered. 81 * Note: This basic version assumes all results have the same error type E. 82 * And collects values into an array T[]. 83 * @param results An array of Result instances. 84 * @returns A single Result. Ok<T[], E> if all succeed, otherwise the first Err<any, E>. 85 */ 86export const combine = <T, E>(results: Result<T, E>[]): Result<T[], E> => { 87 const values: T[] = []; 88 for (const result of results) { 89 if (result.isErr()) { 90 // If we find an error, return it immediately. 91 // We cast the error result to Err<T[], E> for type compatibility. 92 // The T[] part doesn't matter since it's an error state. 93 return err<T[], E>(result.error); 94 } 95 // If it's Ok, collect the value 96 values.push(result.value); 97 } 98 // If no errors were found, return an Ok with the collected values 99 return ok<T[], E>(values); 100}; 101 102// --- Either Type (kept separate for now) --- 103 104export type Either<L, A> = Left<L, A> | Right<L, A>; 105 106export class Left<L, A> { 107 readonly value: L; 108 109 constructor(value: L) { 110 this.value = value; 111 } 112 113 isLeft(): this is Left<L, A> { 114 return true; 115 } 116 117 isRight(): this is Right<L, A> { 118 return false; 119 } 120} 121 122export class Right<L, A> { 123 readonly value: A; 124 125 constructor(value: A) { 126 this.value = value; 127 } 128 129 isLeft(): this is Left<L, A> { 130 return false; 131 } 132 133 isRight(): this is Right<L, A> { 134 return true; 135 } 136} 137 138export const left = <L, A>(l: L): Either<L, A> => { 139 return new Left(l); 140}; 141 142export const right = <L, A>(a: A): Either<L, A> => { 143 return new Right<L, A>(a); 144};