Created
January 29, 2024 23:00
-
-
Save swikars1/b7606c85372774b9a37ce9792be6d9d7 to your computer and use it in GitHub Desktop.
Implementation of Rust like Result<T,E> and Option<T> 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
| interface SomeType<T> { | |
| type: "some"; | |
| value: T; | |
| /*** Returns the value of the Option if it exists, otherwise throws an error.*/ | |
| unwrap(): T; | |
| /*** Returns the value of the Option if it exists, otherwise returns the provided default value.*/ | |
| unwrapOr(defaultValue: T): T; | |
| /*** Returns the value of the Option if it exists, otherwise calls the provided function and returns its result.*/ | |
| unwrapOrElse(fn: () => T): T; | |
| /*** Returns true if the Option contains a value, false otherwise.*/ | |
| isSome(this: Option<T>): this is SomeType<T>; | |
| /*** Returns true if the Option does not contain a value, false otherwise.*/ | |
| isNone(this: Option<T>): this is NoneType; | |
| } | |
| interface NoneType { | |
| type: "none"; | |
| /*** Throws an error because None does not contain a value.*/ | |
| unwrap(): never; | |
| /*** Returns the provided default value because None does not contain a value.*/ | |
| unwrapOr<T>(defaultValue: T): T; | |
| /*** Calls the provided function and returns its result because None does not contain a value.*/ | |
| unwrapOrElse<T>(fn: () => T): T; | |
| /*** Returns true if the Option contains a value, false otherwise.*/ | |
| isSome<T>(this: Option<T>): this is SomeType<T>; | |
| /*** Returns true if the Option does not contain a value, false otherwise.*/ | |
| isNone<T>(this: Option<T>): this is NoneType; | |
| } | |
| export type Option<T> = SomeType<T> | NoneType; | |
| /** | |
| * Creates an Option with a value. | |
| * @param value The value to be wrapped in the Option. | |
| * @returns An Option with the 'some' type and the provided value. | |
| */ | |
| export function Some<T>(value: T): Option<T> { | |
| return { | |
| type: "some", | |
| value, | |
| unwrap: () => value, | |
| unwrapOr: () => value, | |
| unwrapOrElse: () => value, | |
| isSome: () => true, | |
| isNone: () => false, | |
| }; | |
| } | |
| /** | |
| * Represents an empty Option with no value. | |
| * @returns An Option with the 'none' type. | |
| */ | |
| export const None: Option<never> = { | |
| type: "none", | |
| unwrap: () => { | |
| throw new Error("Cannot unwrap None"); | |
| }, | |
| unwrapOr: <T>(defaultValue: T) => defaultValue, | |
| unwrapOrElse: <T>(fn: () => T) => fn(), | |
| isSome: () => false, | |
| isNone: () => true, | |
| }; | |
| //Freezing the None object to prevent any changes. | |
| Object.freeze(None); | |
| interface Left<T, E> { | |
| type: "error"; | |
| error: E; | |
| /*** Returns the value of the Result if it is successful, otherwise throws an error.*/ | |
| unwrap(): T; | |
| /*** Returns the value of the Result if it is successful, otherwise returns the provided default value.*/ | |
| unwrapOr(defaultValue: T): T; | |
| /*** Returns the value of the Result if it is successful, otherwise calls the provided function with the error and returns its result.*/ | |
| unwrapOrElse(fn: (error: E) => T): T; | |
| /*** Returns true if the Result is an error, false otherwise.*/ | |
| isErr(this: Result<T, E>): this is Left<T, E>; | |
| /*** Returns true if the Result is successful, false otherwise.*/ | |
| isOk(this: Result<T, E>): this is Right<T, E>; | |
| } | |
| /** Represents a successful computation.*/ | |
| interface Right<T, E> { | |
| type: "ok"; | |
| value: T; | |
| /*** Returns the value of the Result.*/ | |
| unwrap(): T; | |
| /*** Returns the value of the Result.*/ | |
| unwrapOr(defaultValue: T): T; | |
| /*** Returns the value of the Result.*/ | |
| unwrapOrElse(fn: (error: E) => T): T; | |
| /*** Returns true if the Result is an error, false otherwise.*/ | |
| isErr(this: Result<T, E>): this is Left<T, E>; | |
| /*** Returns true if the Result is successful, false otherwise.*/ | |
| isOk(this: Result<T, E>): this is Right<T, E>; | |
| } | |
| export type Result<T, E> = Left<T, E> | Right<T, E>; | |
| /** Creates a successful Result with the given value. | |
| * @param value The value of the successful computation. | |
| * @returns A Result with the 'ok' type and the provided value.*/ | |
| export function Ok<T, E>(value: T): Result<T, E> { | |
| return { | |
| type: "ok", | |
| value, | |
| unwrap: () => value, | |
| unwrapOr: () => value, | |
| unwrapOrElse: () => value, | |
| isErr: () => false, | |
| isOk: () => true, | |
| }; | |
| } | |
| /** | |
| * Creates a failed Result with the given error. | |
| * @param error The error that caused the computation to fail. | |
| * @returns A Result with the 'error' type and the provided error. | |
| */ | |
| export function Err<T, E>(error: E): Result<T, E> { | |
| return { | |
| type: "error", | |
| error, | |
| unwrap: () => { | |
| throw error; | |
| }, | |
| unwrapOr: (defaultValue: T) => defaultValue, | |
| unwrapOrElse: (fn: (error: E) => T) => fn(error), | |
| isErr: () => true, | |
| isOk: () => false, | |
| }; | |
| } | |
| function divide( | |
| numerator: number, | |
| denominator: number | |
| ): Result<number, string> { | |
| if (denominator === 0) { | |
| return Err("no zero in denominator"); | |
| } else { | |
| return Ok(numerator / denominator); | |
| } | |
| } | |
| const result = divide(3, 2); | |
| if (result.isErr()) { | |
| console.error(); | |
| } else { | |
| console.log(result.unwrap()); // unwrap() has actual value | |
| } | |
| // We can also use unwrapOr and unwrapOrElse | |
| console.log(result.unwrapOr(0)); // Return 0 if the result is an error. | |
| console.log( | |
| result.unwrapOrElse((error) => { | |
| console.error(error); | |
| return 0; | |
| }) | |
| ); //Do some additional stuff if the result is an error. | |
| function find<T>(arr: T[], predicate: (value: T) => boolean): Option<T> { | |
| for (const value of arr) { | |
| if (predicate(value)) { | |
| return Some(value); | |
| } | |
| } | |
| return None; | |
| } | |
| const val = find([1, 2, 4, 5, 3], (a) => a === 2); | |
| if (val.isSome()) { | |
| console.log(val.unwrap()); | |
| } else { | |
| console.log("no value found"); | |
| } | |
| val.unwrapOr(0); // return 0 if no value | |
| // do something inside a fn block return 0 if no value | |
| val.unwrapOrElse(() => { | |
| // do something | |
| return 0; | |
| }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment