Skip to content

Instantly share code, notes, and snippets.

@jRimbault
Last active May 26, 2021 11:44
Show Gist options
  • Save jRimbault/fa99fcd4b78110b94658e9d1bf62ea0a to your computer and use it in GitHub Desktop.
Save jRimbault/fa99fcd4b78110b94658e9d1bf62ea0a to your computer and use it in GitHub Desktop.
interface ResultMethods<T, E> {
ok(): T | null,
err(): E | null,
unwrap(): T | never,
unwrapErr(): E | never,
expect(message: string): T | never,
expectErr(message: string): E | never,
map<U>(f: (value: T) => U): Result<U, E>,
mapErr<U>(f: (error: E) => U): Result<T, U>,
andThen<U>(f: (value: T) => Result<U, E>): Result<U, E>,
}
interface Ok<T, E> extends ResultMethods<T, E> {
isOk: true,
isErr: false,
value: T,
ok(): T,
err(): null,
unwrap(): T,
unwrapErr(): never,
expect(message: string): T,
expectErr(message: string): never,
}
interface Error<T, E> extends ResultMethods<T, E> {
isOk: false,
isErr: true,
error: E,
ok(): null,
err(): E,
unwrap(): never,
unwrapErr(): E,
expect(message: string): never,
expectErr(message: string): E,
}
type Methods<T, E> = keyof ResultMethods<T, E>;
type OkProps<T, E> = Omit<Ok<T, E>, Methods<T, E>>;
type ErrorProps<T, E> = Omit<Error<T, E>, Methods<T, E>>;
type ResultProp<T, E> = OkProps<T, E> | ErrorProps<T, E>;
export type Result<T, E> = Ok<T, E> | Error<T, E>;
type OkMethods<T> = {
ok(): T,
err(): null,
unwrap(): T,
unwrapErr(): never,
expect(message: string): T,
expectErr(message: string): never,
};
type ErrorMethods<E> = {
ok(): null,
err(): E,
unwrap(): never,
unwrapErr(): E,
expect(message: string): never,
expectErr(message: string): E,
};
type ResultMethods<T, E> = {
map<U>(f: (value: T) => U): Result<U, E>,
mapErr<U>(f: (error: E) => U): Result<T, U>,
andThen<U>(f: (value: T) => Result<U, E>): Result<U, E>,
};
type OkProp<T> = { isOk: true, isErr: false, value: T };
type ErrorProp<E> = { isOk: false, isErr: true, error: E };
type ResultProp<T, E> = OkProp<T> | ErrorProp<E>;
type Ok<T> = OkProp<T> & OkMethods<T>;
type Error<E> = ErrorProp<E> & ErrorMethods<E>;
export type Result<T, E> = (Ok<T> | Error<E>) & ResultMethods<T, E>;
export const Result = { ok, err } as const;
export function ok<T, E>(value: T): Result<T, E> {
return result({ isOk: true, isErr: false, value });
}
interface ToString { toString(): string }
export function err<T, E extends ToString>(error: E): Result<T, E> {
return result({ isOk: false, isErr: true, error });
}
function result<T, E>(props: ResultProp<T, E>): Result<T, E> {
return {
...props,
ok: function() { return this.isOk ? this.value : null; },
err: function() { return this.isErr ? this.error : null; },
unwrap: function() { return unwrap(this); },
unwrapErr: function() { return unwrapErr(this); },
expect: function(message) { return expect(this, message); },
expectErr: function(message) { return expectErr(this, message); },
map: function(f) { return map(this, f); },
mapErr: function(f) { return mapErr(this, f); },
andThen: function(f) { return andThen(this, f); },
} as Result<T, E>;
}
function unwrap<T, E extends ToString>(result: Result<T, E>): T | never {
if (result.isErr) {
throw new Error(result.error.toString());
}
return result.value;
}
function unwrapErr<T, E>(result: Result<T, E>): E | never {
return expectErr(result, "Result was ok");
}
function expect<T, E extends ToString>(result: Result<T, E>, message: string): T | never {
if (result.isErr) {
throw new Error(message);
}
return result.value;
}
function expectErr<T, E>(result: Result<T, E>, message: string): E | never {
if (result.isOk) {
throw new Error(message);
}
return result.error;
}
function map<T, U, E>(result: Result<T, E>, f: (i: T) => U): Result<U, E> {
if (result.isErr) {
return err(result.error);
}
return ok(f(result.value));
}
function mapErr<T, U, E>(result: Result<T, E>, f: (i: E) => U): Result<T, U> {
if (result.isErr) {
return err(f(result.error));
}
return ok(result.value);
}
function andThen<T, U, E>(result: Result<T, E>, f: (i: T) => Result<U, E>): Result<U, E> {
if (result.isErr) {
return err(result.error);
}
return f(result.value);
}
@jRimbault
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment