Skip to content

Instantly share code, notes, and snippets.

@anaisbetts
Created April 9, 2020 05:59
Show Gist options
  • Save anaisbetts/0c0a7c23145aef13f3e1773b239b1907 to your computer and use it in GitHub Desktop.
Save anaisbetts/0c0a7c23145aef13f3e1773b239b1907 to your computer and use it in GitHub Desktop.
export abstract class Result<T> {
abstract isOk(): boolean;
abstract isErr(): boolean;
abstract ok(): T | undefined;
abstract err(): Error | undefined;
static Ok<T>(val: T): Result<T> {
return new OkValue(val);
}
static Err<T>(err: Error): Result<T> {
return new ErrorValue(err);
}
static fromPromise<T>(val: Promise<T>): Promise<Result<T>> {
return val.then(
x => Result.Ok(x),
ex => Result.Err(ex));
}
expect(): T {
if (this.isErr()) {
throw new Error('Value is an Error and we expected an Ok');
}
return this.ok()!;
}
expectErr(): Error {
if (this.isOk()) {
throw new Error('Value is an Error and we expected an Ok');
}
return this.err()!;
}
contains(val: T): boolean {
if (this.isErr()) return false;
return (this.expect() === val);
}
map<N>(fn: ((val: T) => N)): Result<N> {
if (this.isErr()) {
return Result.Err<N>(this.expectErr());
}
return Result.Ok(fn(this.expect()));
}
mapOrElse<N>(orElse: N, fn: ((val: T) => N)): N {
if (this.isErr()) return orElse;
return fn(this.expect());
}
mapErr(fn: ((val: Error) => Error)): Result<T> {
if (this.isOk()) return this;
return Result.Err(fn(this.expectErr()));
}
and<N>(res: Result<N>): Result<N> {
return this.isOk() ? res : Result.Err(this.expectErr());
}
andThen<N>(res: ((val: T) => Result<N>)): Result<N> {
return this.isOk() ? res(this.expect()) : Result.Err(this.expectErr());
}
or(res: Result<T>): Result<T> {
return this.isErr() ? res : this;
}
orElse(res: ((err: Error) => Result<T>)): Result<T> {
return this.isErr() ? res(this.expectErr()) : this;
}
}
class OkValue<T> extends Result<T> {
value: T;
constructor(val: T) {
super();
this.value = val;
}
isOk(): boolean {
return true;
}
isErr(): boolean {
return false;
}
ok(): T | undefined {
return this.value;
}
err(): Error | undefined {
return undefined;
}
}
class ErrorValue<T> extends Result<T> {
value: Error;
constructor(val: Error) {
super();
this.value = val;
}
isOk(): boolean {
return false;
}
isErr(): boolean {
return true;
}
ok(): T | undefined {
return undefined;
}
err(): Error | undefined {
return this.value;
}
}
import { useEffect, useState } from 'react';
import { from, Observable } from 'rxjs';
import { Result } from './result';
export function useObservable<T>(
target: () => Observable<T>,
initial?: T,
): Result<T | undefined> {
const [ret, setter] = useState(Result.Ok(initial));
const [obs] = useState(target);
useEffect(
() => {
const sub = obs.subscribe(
x => setter(Result.Ok(x)),
ex => setter(Result.Err(ex)));
return sub.unsubscribe.bind(sub);
},
[obs],
);
return ret;
}
export function usePromise<T>(
target: () => Promise<T>,
initial?: T,
): Result<T | undefined> {
return useObservable(() => from(target()), initial);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment