Skip to content

Instantly share code, notes, and snippets.

@kurtbuilds
Last active November 15, 2021 21:17
Show Gist options
  • Save kurtbuilds/aa72f8ce9a2b07aa2f85fe520544f8ee to your computer and use it in GitHub Desktop.
Save kurtbuilds/aa72f8ce9a2b07aa2f85fe520544f8ee to your computer and use it in GitHub Desktop.
//Typescript version of Rust's Result type
interface IValue<T> {
type: 'value'
value: T
}
interface IError<E extends Error> {
type: 'error'
error: E
}
type ResultType<T, E extends Error> = IValue<T> | IError<E>
export class Result<T, E extends Error> {
constructor(public result: ResultType<T, E>) { }
static value<T>(value: T): Result<T, any> {
return new Result({
type: 'value',
value,
})
}
static error<E extends Error>(error: E): Result<any, E> {
return new Result({
type: 'error',
error,
})
}
unwrap(): T {
switch (this.result.type) {
case 'value': return this.result.value
case 'error': throw this.result.error
}
}
unwrap_err(): E {
switch (this.result.type) {
case 'error': return this.result.error
case 'value': throw new Error('Tried to unwrap_err on result, but not an error.')
}
}
map<S>(f: (value: T) => S): Result<S, E> {
switch (this.result.type) {
case 'value':
return new Result<S, E>({
type: 'value',
value: f(this.result.value),
})
case 'error': return new Result<S, E>(this.result)
}
}
async amap<S>(f: (value: T) => Promise<S>): Promise<Result<S, E>> {
switch (this.result.type) {
case 'value':
return new Result<S, E>({
type: 'value',
value: (await f(this.result.value)),
})
case 'error':
return new Result<S, E>(this.result)
}
}
unwrap_or(d: T): T {
switch (this.result.type) {
case 'value': return this.result.value
case 'error': return d
}
}
is_ok(): boolean {
return this.result.type === 'value'
}
is_err(): boolean {
return this.result.type === 'error'
}
}
export function Ok<T>(v: T): Result<T, any> {
return Result.value(v)
}
export function Err<E extends Error>(e: E): Result<any, E> {
return Result.error(e)
}
export function Maybe<T, E extends Error>(v: T | null | undefined): Result<T, Error> {
if (v === null || v === undefined) {
return Err(new Error('Not found.'))
} else {
return Ok(v!)
}
}
export function Serr(message: string): Result<any, Error> {
return Result.error(new Error(message))
}
//Other Rust primitives, not directly related to Result
/** Can be used for exhaustive checks, ex:
let name: 'fetch-transactions' | 'query-email-receipts' | 'spending-summary' | 'transaction-review'
if (name === 'query-email-receipts') {
return handle_email_receipt_query_job;
} else if (name === 'fetch-transactions') {
return handle_fetch_transactions
} else if (name === 'spending-summary') {
return unimplemented()
} else if (name === 'transaction-review') {
return unimplemented()
} else {
// if any type possibility was unhandled, this would report a typecheck error at checktime.
// this happens because infallible gives its parameter the `never` type, meaning there can
// be no instance of an object of that type.
infallible(name)
}
*/
export function infallible(t: never): never {
throw new Error('Reached infallible but that shouldn\'t be possible.')
}
export function unimplemented(): never {
throw new Error('This codepath has not been implemented.')
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment