Skip to content

Instantly share code, notes, and snippets.

@swikars1
Created January 29, 2024 23:00
Show Gist options
  • Select an option

  • Save swikars1/b7606c85372774b9a37ce9792be6d9d7 to your computer and use it in GitHub Desktop.

Select an option

Save swikars1/b7606c85372774b9a37ce9792be6d9d7 to your computer and use it in GitHub Desktop.
Implementation of Rust like Result<T,E> and Option<T> in Typescript
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