UNPKG

@rustresult/result

Version:

Rust-like Result and ResultAsync for Javascript

612 lines (611 loc) 20 kB
import type { ResultAsync } from './ResultAsync'; import type { Optional } from './types.internal'; /** * The interface of `Result` that defines the methods that `Result` should support. * * This package includes a default implementation of `Result` and factory functions `Ok` and `Err`, * which should meet your requirements in most cases. * * ref: * - https://doc.rust-lang.org/std/result/index.html * - https://doc.rust-lang.org/std/result/enum.Result.html */ export interface Result<T, E> { /** * Returns `true` if the result is `Ok`. * * Examples: * * ``` * import { Err, Ok, type Result } from 'rustlike-result'; * * const x: Result<number, string> = Ok(2); * assert(x.isOk() === true); * * const y: Result<number, string> = Err('Some error message'); * assert(y.isOk() === false); * ``` * * ref: https://doc.rust-lang.org/std/result/enum.Result.html#method.is_ok */ isOk(): this is Result<T, never>; /** * Returns `true` if the result is `Ok` and the value inside of it matches a predicate. * * Examples: * * ``` * import { Err, Ok, type Result } from 'rustlike-result'; * * const x: Result<number, string> = Ok(2); * assert(x.isOkAnd((value) => value > 1) === true); * * const y: Result<number, string> = Ok(0); * assert(y.isOkAnd((value) => value > 1) === false); * * const z: Result<number, string> = Err('Some error message'); * assert(z.isOkAnd((value) => value > 1) === false); * ``` * * ref: https://doc.rust-lang.org/std/result/enum.Result.html#method.is_ok_and */ isOkAnd(fn: (value: T) => boolean): boolean; /** * Returns `true` if the result is `Err`. * * Examples: * * ``` * import { Err, Ok, type Result } from 'rustlike-result'; * * const x: Result<number, string> = Ok(-3); * assert(x.isErr() === false); * * const y: Result<number, string> = Err('Some error message'); * assert(y.isErr() === true); * ``` * * ref: https://doc.rust-lang.org/std/result/enum.Result.html#method.is_err */ isErr(): this is Result<never, E>; /** * Returns `true` if the result is `Err` and the value inside of it matches a predicate. * * Examples: * * ``` * import { Err, Ok, type Result } from 'rustlike-result'; * * enum ErrorKind { * NOT_FOUND, * PERMISSION_DENIED, * } * * const x: Result<number, ErrorKind> = Err(ErrorKind.NOT_FOUND); * assert(x.isErrAnd((value) => value === ErrorKind.NOT_FOUND) === true); * * const y: Result<number, ErrorKind> = Err(ErrorKind.PERMISSION_DENIED); * assert(y.isErrAnd((value) => value === ErrorKind.NOT_FOUND) === false); * * const z: Result<number, ErrorKind> = Ok(123); * assert(z.isErrAnd((value) => value === ErrorKind.NOT_FOUND) === false); * ``` * * ref: https://doc.rust-lang.org/std/result/enum.Result.html#method.is_err_and */ isErrAnd(fn: (err: E) => boolean): boolean; /** * Converts from `Result<T, E>` to `Optional<T>` and discarding the error, if any. * * Examples: * * ``` * import { Err, Ok, type Result } from 'rustlike-result'; * * const x: Result<number, string> = Ok(2); * assert(x.ok() === 2); * * const y: Result<number, string> = Err('Some error message'); * assert(y.ok() === undefined); * ``` * * ref: https://doc.rust-lang.org/std/result/enum.Result.html#method.ok */ ok(): Optional<T>; /** * Converts from `Result<T, E>` to `Optional<E>` and discarding the success value, if any. * * Examples: * * ``` * import { Err, Ok, type Result } from 'rustlike-result'; * * const x: Result<number, string> = Ok(2); * assert(x.err() === undefined); * * const y: Result<number, string> = Err('Some error message'); * assert(y.err() === 'Some error message'); * ``` * * ref: https://doc.rust-lang.org/std/result/enum.Result.html#method.err */ err(): Optional<E>; /** * Maps a `Result<T, E>` to `Result<U, E>` by applying a function to a contained `Ok` value, * leaving an `Err` value untouched. * * This function can be used to compose the results of two functions. * * Examples: * * ``` * import { Ok, type Result } from 'rustlike-result'; * * const x: Result<string, string> = Ok('foo'); * assert(x.map((value) => value.length).ok() === 3); * ``` * * ref: https://doc.rust-lang.org/std/result/enum.Result.html#method.map */ map<U>(op: (value: T) => U): Result<U, E>; /** * Returns the provided `fallback` (if `Err`), or applies a function to the contained value (if `Ok`). * * Arguments passed to `mapOr` are eagerly evaluated; * if you are passing the result of a function call, * it is recommended to use `mapOrElse`, which is lazily evaluated. * * Examples: * * ``` * import { Err, Ok, type Result } from 'rustlike-result'; * * const x: Result<string, string> = Ok('foo'); * assert(x.mapOr(42, (value) => value.length) === 3); * * const y: Result<string, string> = Err('bar'); * assert(y.mapOr(42, (value) => value.length) === 42); * ``` * * ref: https://doc.rust-lang.org/std/result/enum.Result.html#method.map_or */ mapOr<U>(fallback: U, map: (value: T) => U): U; /** * Maps a `Result<T, E>` to `U` by applying fallback function `fallback` to a contained `Err` value, * or function `map` to a contained `Ok` value. * * This function can be used to unpack a successful result while handling an error. * * Examples: * * ``` * import { Err, Ok, type Result } from 'rustlike-result'; * * const k = 21; * * const x: Result<string, string> = Ok('foo'); * assert(x.mapOrElse((err) => k * 2, (value) => value.length) === 3); * * const y: Result<string, string> = Err('bar'); * assert(y.mapOrElse((err) => k * 2, (value) => value.length) === 42); * ``` * * ref: https://doc.rust-lang.org/std/result/enum.Result.html#method.map_or_else */ mapOrElse<U>(fallback: (err: E) => U, map: (value: T) => U): U; /** * Maps a `Result<T, E>` to `Result<T, F>` by applying a function to a contained `Err` value, * leaving an `Ok` value untouched. * * This function can be used to pass through a successful result while handling an error. * * Examples: * * ``` * import { Err, type Result } from 'rustlike-result'; * * const x: Result<number, Error> = Err(new Error('Some error message')); * assert(x.mapErr((err) => err.message).err() === 'Some error message'); * ``` * * ref: https://doc.rust-lang.org/std/result/enum.Result.html#method.map_err */ mapErr<F>(op: (err: E) => F): Result<T, F>; /** * Calls the provided closure with a reference to the contained value if `Ok`. * * Examples: * * ``` * import { resultifySync } from 'rustlike-result'; * * const num = resultifySync<SyntaxError>()(JSON.parse)('4') * .inspect((value: number) => console.log(`original: ${value}`)) * .map((value) => value ** 3) * .expect('failed to parse number'); * assert(num === 64); * ``` * * ref: https://doc.rust-lang.org/std/result/enum.Result.html#method.inspect */ inspect(fn: (value: T) => void): this; /** * Calls the provided closure with a reference to the contained value if `Err`. * * Examples: * * ``` * import { resultifySync } from 'rustlike-result'; * * const num = resultifySync<SyntaxError>()(JSON.parse)('asdf') * .inspectErr((err) => console.log(`failed to parse json string: ${err.message}`)); * assert(num.err() instanceof SyntaxError); * ``` * * ref: https://doc.rust-lang.org/std/result/enum.Result.html#method.inspect_err */ inspectErr(fn: (err: E) => void): this; /** * Returns the contained `Ok` value. * * Because this function may throw an error, its use is generally discouraged. * Instead, prefer to call `unwrapOr`, `unwrapOrElse`. * * Throws an Error if itself is `Err`, * with an error message including the passed message, and the content of the `Err`. * * Examples: * * ``` * import { Err, type Result } from 'rustlike-result'; * * const x: Result<number, string> = Err('emergency failure'); * x.expect('Failed to operate'); // throws Error('Failed to operate: emergency failure') * ``` * * ref: https://doc.rust-lang.org/std/result/enum.Result.html#method.expect */ expect(msg: string): T; /** * Returns the contained `Ok` value. * * Because this function may throw an error, its use is generally discouraged. * Instead, prefer to call `unwrapOr`, `unwrapOrElse`. * * Throws an Error if itself is `Err`, with an error message provided by the `Err`'s value. * * Examples: * * ``` * import { Err, Ok, type Result } from 'rustlike-result'; * * const x: Result<number, string> = Ok(2); * assert(x.unwrap() === 2); * * const y: Result<number, string> = Err('emergency failure'); * y.unwrap(); // throws Error('emergency failure') * ``` * * ref: https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap */ unwrap(): T; /** * Returns the contained `Err` value. * * Throws an Error if itself is `Err`, with an error message provided by the `Ok`'s value. * * Examples: * * ``` * import { Ok, type Result } from 'rustlike-result'; * * const x: Result<number, string> = Ok(10); * x.expectErr('Testing expectErr'); // throws Error('Testing expectErr: 10') * ``` * * ref: https://doc.rust-lang.org/std/result/enum.Result.html#method.expect_err */ expectErr(msg: string): E; /** * Returns the contained `Err` value. * * Throws an Error if itself is `Ok`, with an error message provided by the `Ok`'s value. * * Examples: * * ``` * import { Ok, type Result } from 'rustlike-result'; * * const x: Result<number, string> = Err('emergency failure'); * assert(x.unwrapErr() === 'emergency failure'); * * const y: Result<number, string> = Ok(2); * y.unwrapErr(); // throws Error(2) * ``` * * ref: https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap_err */ unwrapErr(): E; /** * Returns the contained `Ok` value or a provided default. * * Arguments passed to `unwrapOr` are eagerly evaluated; * if you are passing the result of a function call, * it is recommended to use `unwrapOrElse`, which is lazily evaluated. * * Examples: * * ``` * import { Err, Ok, type Result } from 'rustlike-result'; * * const $default = 2; * const x: Result<number, string> = Ok(9); * assert(x.unwrapOr($default) === 9); * * const y: Result<number, string> = Err('error'); * assert(y.unwrapOr($default) === $default); * ``` * * ref: https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap_or */ unwrapOr(fallback: T): T; /** * Returns the contained `Ok` value or computes it from a closure. * * Examples: * * ``` * import { Err, Ok } from 'rustlike-result'; * * const count = (err: string) => err.length; * assert(Ok<number, string>(2).unwrapOrElse(count) === 2); * assert(Err<number, string>('foo').unwrapOrElse(count) === 3); * ``` * * ref: https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap_or_else */ unwrapOrElse(op: (err: E) => T): T; /** * Returns the contained `Ok` value, without checking that the value is not an `Err`. * * **SAFETY**: Calling this method on an `Err` is undefined behavior. * The safety contract must be upheld by the caller. * * Examples: * * ``` * import { Err, Ok, type Result } from 'rustlike-result'; * * const x: Result<number, string> = Ok(2); * assert(x.unwrapUnchecked() === 2); * * const y: Result<number, string> = Err('emergency failure'); * y.unwrapUnchecked(); * ``` * * ref: https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap_unchecked */ unwrapUnchecked(): T; /** * Returns the contained `Err` value, without checking that the value is not an `Ok`. * * **SAFETY**: Calling this method on an `Ok` is undefined behavior. * The safety contract must be upheld by the caller. * * Examples: * * ``` * import { Err, Ok, type Result } from 'rustlike-result'; * * const x: Result<number, string> = Ok(2); * x.unwrapErrUnchecked(); * * const y: Result<number, string> = Err('emergency failure'); * assert(y.unwrapErrUnchecked() === 'emergency failure'); * ``` * * ref: https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap_err_unchecked */ unwrapErrUnchecked(): E; /** * Returns `res` if itself is `Ok`, otherwise returns the `Err` value of itself. * * Arguments passed to `and` are eagerly evaluated; * if you are passing the result of a function call, it is recommended to use `andThen`, which is lazily evaluated. * * Examples: * * ``` * import { Err, Ok, type Result } from 'rustlike-result'; * * let x: Result<number, string>; * let y: Result<string, string>; * * x = Ok(2); * y = Err('late error'); * assert(x.and(y).equal(Err('late error'))); * * x = Err('early error'); * y = Ok('foo'); * assert(x.and(y).equal(Err('early error'))); * * x = Err('not a 2'); * y = Err('late error'); * assert(x.and(y).equal(Err('not a 2'))); * * x = Ok(2); * y = Ok('different result type'); * assert(x.and(y).equal(Ok('different result type'))); * ``` * * ref: https://doc.rust-lang.org/std/result/enum.Result.html#method.and */ and<U>(res: Result<U, E>): Result<U, E>; /** * Calls `op` if itself is `Ok`, otherwise returns the `Err` value of itself. * * This function can be used for control flow based on `Result` values. * * Examples: * * ``` * import { Err, Ok, resultifySync } from 'rustlike-result'; * * const parseJSON = (json: string) => * resultifySync<SyntaxError>()(JSON.parse)(json).mapErr((err) => err.message); * * assert(Ok<string, string>('2').andThen(parseJSON).equal(Ok(2))); * assert( * Ok<string, string>('asdf') * .andThen(parseJSON) * .equal(Err('Unexpected token \'a\', "asdf" is not valid JSON')), * ); * ``` * * ref: https://doc.rust-lang.org/std/result/enum.Result.html#method.and_then */ andThen<U>(op: (value: T) => Result<U, E>): Result<U, E>; /** * Returns `res` if itself is `Err`, otherwise returns the `Ok` value of itself. * * Arguments passed to `or` are eagerly evaluated; * if you are passing the result of a function call, it is recommended to use `orElse`, which is lazily evaluated. * * Examples: * * ``` * import { Err, Ok, type Result } from 'rustlike-result'; * * let x: Result<number, string>; * let y: Result<number, string>; * * x = Ok(2); * y = Err('late error'); * assert(x.or(y).equal(Ok(2))); * * x = Err('early error'); * y = Ok(2); * assert(x.or(y).equal(Ok(2))); * * x = Err('not a 2'); * y = Err('late error'); * assert(x.or(y).equal(Err('late error'))); * * x = Ok(2); * y = Ok(100); * assert(x.or(y).equal(Ok(2))); * ``` * * ref: https://doc.rust-lang.org/std/result/enum.Result.html#method.or */ or<F>(res: Result<T, F>): Result<T, F>; /** * Calls `op` if the result is `Err`, otherwise returns the `Ok` value of self. * * This function can be used for control flow based on `Result` values. * * Examples: * * ``` * import { Err, Ok, type Result } from 'rustlike-result'; * * const sq = (num: number): Result<number, number> => Ok(num * num); * const err = (num: number): Result<number, number> => Err(num); * * assert(Ok(2).orElse(sq).orElse(sq).equal(Ok(2))); * assert(Ok(2).orElse(err).orElse(sq).equal(Ok(2))); * assert(Err<number, number>(3).orElse(sq).orElse(err).equal(Ok(9))); * assert(Err<number, number>(3).orElse(err).orElse(err).equal(Err(3))); * ``` * * ref: https://doc.rust-lang.org/std/result/enum.Result.html#method.or_else */ orElse<F>(op: (err: E) => Result<T, F>): Result<T, F>; /** * Transposes a `Result` of an optional value into an optional of a `Result`. * * `Ok(undefined | null)` will be mapped to `undefined`. * `Ok(_)` and `Err(_)` will be mapped to `Ok(_)` and `Err(_)`. * * Examples: * * ``` * import { Err, Ok, type Result } from 'rustlike-result'; * * type SomeErr = unknown; * * let x: Result<number | undefined | null, SomeErr>; * let y: Result<number, SomeErr> | undefined; * * x = Ok(5); * y = Ok(5); * assert(x.transpose()!.equal(y)); * * x = Ok(undefined); * y = undefined; * assert(x.transpose() === y); * * x = Ok(null); * y = undefined; * assert(x.transpose() === y); * ``` * * ref: https://doc.rust-lang.org/std/result/enum.Result.html#method.transpose */ transpose(): Optional<Result<T & NonNullable<unknown>, E>>; /** * Returns `true` if `self` equals to `other`. * * Examples: * * ``` * import { Err, Ok } from 'rustlike-result'; * * assert(Ok(1).equal(Ok(1))); * assert(Ok(NaN).equal(Ok(NaN))); * assert(Err('err').equal(Err('err'))); * * assert(Ok(1).equal(Ok(2)) === false); * assert(Err('err 1').equal(Err(-1)) === false); * * assert(Ok(Ok(1)).equal(Ok(Ok(1)))); * assert(Ok(Err('err')).equal(Ok(Err('err')))); * assert(Err(Err('err')).equal(Err(Err('err')))); * assert(Err(Ok(1)).equal(Err(Ok(1)))); * * assert(Ok(Ok(1)).equal(Ok(Ok(2))) === false); * assert(Ok(Ok(1)).equal(Ok(Err('err'))) === false); * assert(Err(Ok(1)).equal(Err(Err('err'))) === false); * * assert(Ok([1]).equal(Ok([1])) === false); * assert(Ok({ foo: 1 }).equal(Ok({ foo: 1 })) === false); * assert(Ok(Ok([1])).equal(Ok(Ok([1]))) === false); * assert(Ok(Ok({ foo: 1 })).equal(Ok(Ok({ foo: 1 }))) === false); * ``` */ equal(other: Result<unknown, unknown>): boolean; /** * Converts this result to an async `Result` so it can work in asynchronous code. * * Examples: * * ``` * import { Ok } from 'rustlike-result'; * * function fn(value: number): Promise<number> { * // do something asynchronously * return Promise.resolve(value ** 2); * } * * const num = await Ok<number, string>(3) * .async() * .map(fn) * .inspectErr((err) => { * console.log(err); * }) * .ok(); * assert(num === 9); * ``` */ async(): ResultAsync<T, E>; }