rstypes 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,135 @@
1
+ import { Err, Ok, Result } from "./result";
2
+ /**
3
+ * An optional value.
4
+ *
5
+ * ### Example
6
+ * ```ts
7
+ * function divide(numerator: number, denominator: number): Option<number> {
8
+ * if(y === 0) {
9
+ * return None;
10
+ * } else {
11
+ * return Some(numerator / denominator);
12
+ * }
13
+ * }
14
+ *
15
+ * let result = divide(2.0, 3.0);
16
+ * result.match({
17
+ * Some(n) { console.log(`Result: ${x}`); },
18
+ * None() { console.log("Cannot divide by 0")}
19
+ * })
20
+ * ```
21
+ */
22
+ export type Option<T> = Some<T> | None<T>;
23
+ /**
24
+ * Wrap a function that can return `undefined`, `null` or `NaN`, to instead return an Option,
25
+ * which will be None in the above cases.
26
+ */
27
+ export declare function as_option<A extends any[], T>(fn: (...args: A) => T): (...args: A) => Option<T>;
28
+ /**
29
+ * Common method signatures for Option types.
30
+ */
31
+ interface OptionMethods<T> {
32
+ /**
33
+ * Returns `other` if the result is `Some`, or `None` otherwise.
34
+ * @param other Option to return if the option is `Some`
35
+ */
36
+ and<U>(other: Option<U>): Option<U>;
37
+ /**
38
+ * Return the contained `Some` value. Will throw a hard error with the specified message if called on `None`.
39
+ * @param message Custom message to throw if `None`
40
+ */
41
+ expect(message: string): T;
42
+ /**
43
+ * returns `true` if the option is `Some`, `false` if `None`.
44
+ */
45
+ is_some(): this is Some<T>;
46
+ /**
47
+ * returns `true` if the option is `Some` and the value satisfies
48
+ * the given predicate, `false` otherwise.
49
+ */
50
+ is_some_and(predicate: (value: T) => boolean): boolean;
51
+ /**
52
+ * returns `false` if the option is `Some`, `true` if `None`.
53
+ */
54
+ is_none(): this is None<T>;
55
+ /**
56
+ * Returns `true` if the option is `None` or the value satisfies
57
+ * the given predicate, `false` otherwise
58
+ */
59
+ is_none_or(predicate: (value: T) => boolean): boolean;
60
+ /**
61
+ * Maps an `Option<T>` into an `Option<U>`.
62
+ * Will return `Some(fn(value))` if the option is `Some`, or propagate `None`.
63
+ * @param fn Function to transform the inner `value`
64
+ */
65
+ map<U>(fn: (arg: T) => U): Option<U>;
66
+ /**
67
+ * Pattern-match on the option, running the `Some` or `None` function in the respective cases.
68
+ * @param matcher Object containing a `Some(value)` and `None(error)` function to run
69
+ */
70
+ match<R>(matcher: {
71
+ Some(value: T): R;
72
+ None(): R;
73
+ }): R;
74
+ /**
75
+ * Pattern-match on the option, running the former or latter function
76
+ * in the `Some` or `None` cases respectively.
77
+ * @param on_some Function to run if the option is `Some`
78
+ * @param on_none Function to run if the option is `None`
79
+ */
80
+ match<R>(on_some: (value: T) => R, on_none: () => R): R;
81
+ /**
82
+ * Transforms the Option into a Result, mapping Some(value) to Ok(value)
83
+ * and None to Err(error).
84
+ * @param error Err value to use if the option is `None`
85
+ */
86
+ ok_or<E>(error: E): Result<T, E>;
87
+ /**
88
+ * Returns `other` if the result is `None`, otherwise returns the first option's `Some` value.
89
+ * @param other Option to return if the option is `Some`
90
+ */
91
+ or(other: Option<T>): Option<T>;
92
+ /**
93
+ * Return the contained `Some` value. Will throw a hard error if called on `None`.
94
+ */
95
+ unwrap(): T;
96
+ /**
97
+ * Return the contained `Some` value, or `default_value` if called on `None`.
98
+ * @param default_value Value to use if the option is `None`
99
+ */
100
+ unwrap_or(default_value: T): T;
101
+ /**
102
+ * Return the contained `Some` value, or the result of `otherwise` if called on `None`.
103
+ * @param otherwise Function to run if the option is `None`
104
+ */
105
+ unwrap_or_else(otherwise: () => T): T;
106
+ /**
107
+ * Returns None if either both the option and `other` are `Some` or `None`,
108
+ * or the single `Some(value)` otherwise.
109
+ */
110
+ xor(other: Option<T>): Option<T>;
111
+ }
112
+ /**
113
+ * A present optional value.
114
+ */
115
+ export interface Some<T> extends OptionMethods<T> {
116
+ map<U>(fn: (value: T) => U): Some<U>;
117
+ ok_or<E>(error: E): Ok<T, E>;
118
+ or(other: Option<T>): Some<T>;
119
+ }
120
+ /**
121
+ * No optional value.
122
+ */
123
+ export interface None<T = any> extends OptionMethods<T> {
124
+ and<U>(other: Option<U>): None<U>;
125
+ expect(message: string): never;
126
+ map<U>(fn: (value: T) => U): None<U>;
127
+ ok_or<E>(error: E): Err<T, E>;
128
+ unwrap(): never;
129
+ }
130
+ /**
131
+ * @param value Inner value
132
+ */
133
+ export declare const Some: <T>(value: T) => Some<T>;
134
+ export declare const None: None;
135
+ export {};
package/lib/option.js ADDED
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.None = exports.Some = void 0;
4
+ exports.as_option = as_option;
5
+ const result_1 = require("./result");
6
+ /**
7
+ * Wrap a function that can return `undefined`, `null` or `NaN`, to instead return an Option,
8
+ * which will be None in the above cases.
9
+ */
10
+ function as_option(fn) {
11
+ return (...args) => {
12
+ let out = fn(...args);
13
+ if ((typeof out === "number" && isNaN(out))
14
+ || out === null
15
+ || out === "undefined") {
16
+ return exports.None;
17
+ }
18
+ return (0, exports.Some)(out);
19
+ };
20
+ }
21
+ // Implementations
22
+ const nodeInspect = Symbol.for('nodejs.util.inspect.custom');
23
+ /**
24
+ * @param value Inner value
25
+ */
26
+ const Some = (value) => ({
27
+ and(other) { return other; },
28
+ expect() { return value; },
29
+ is_some() { return true; },
30
+ is_some_and(predicate) { return predicate(value); },
31
+ is_none() { return false; },
32
+ is_none_or(predicate) { return predicate(value); },
33
+ map(fn) { return (0, exports.Some)(fn(value)); },
34
+ match(matcher_or_some) {
35
+ if ("Some" in matcher_or_some) {
36
+ return matcher_or_some.Some(value);
37
+ }
38
+ return matcher_or_some(value);
39
+ },
40
+ ok_or() { return (0, result_1.Ok)(value); },
41
+ or() { return this; },
42
+ unwrap() { return value; },
43
+ unwrap_or() { return value; },
44
+ unwrap_or_else(_) { return value; },
45
+ xor(other) { return other.is_none() ? this : exports.None; },
46
+ toString() { return `Some(${value})`; },
47
+ [nodeInspect](_depth, inspectOptions, inspect) {
48
+ const cyan = inspectOptions.colors ? `\x1b[${inspect.colors.cyan[0]}m` : "";
49
+ const reset = inspectOptions.colors ? `\x1b[${inspect.colors.reset[0]}m` : "";
50
+ return `${cyan}Some${reset}(${inspect(value, inspectOptions)})`;
51
+ }
52
+ });
53
+ exports.Some = Some;
54
+ exports.None = Object.freeze({
55
+ and() { return this; },
56
+ expect(message) { throw Error(message); },
57
+ is_some() { return false; },
58
+ is_some_and() { return false; },
59
+ is_none() { return true; },
60
+ is_none_or() { return true; },
61
+ map() { return exports.None; },
62
+ match(matcher_or_some, none) {
63
+ if ("None" in matcher_or_some) {
64
+ return matcher_or_some.None();
65
+ }
66
+ return none();
67
+ },
68
+ ok_or(err) { return (0, result_1.Err)(err); },
69
+ or(other) { return other; },
70
+ unwrap() { throw Error("Called unwrap on a None value"); },
71
+ unwrap_or(default_value) { return default_value; },
72
+ unwrap_or_else(otherwise) { return otherwise(); },
73
+ xor(other) { return other.is_some() ? other : exports.None; },
74
+ toString() { return "None"; },
75
+ [nodeInspect](_depth, inspectOptions, inspect) {
76
+ const yellow = inspectOptions.colors ? `\x1b[${inspect.colors.yellow[0]}m` : "";
77
+ const reset = inspectOptions.colors ? `\x1b[${inspect.colors.reset[0]}m` : "";
78
+ return `${yellow}None${reset}`;
79
+ }
80
+ });
@@ -0,0 +1,148 @@
1
+ import { None, Option, Some } from "./option";
2
+ /**
3
+ * A succesful value or an expected, recoverable error.
4
+ *
5
+ * ### Example
6
+ * ```ts
7
+ * function parse_int(n: string): Result<number, string> {
8
+ * let maybe = parseInt(n);
9
+ * if(isNaN(maybe)) return Err("Could not parse input");
10
+ * return Ok(maybe);
11
+ * }
12
+ *
13
+ * let result = parse_int(3);
14
+ * result.match({
15
+ * Ok(value) { console.log("Parsed number: ", value) },
16
+ * Err(error) { console.error("Error: ", error)}
17
+ * });
18
+ * ```
19
+ */
20
+ export type Result<T, E> = Ok<T, E> | Err<T, E>;
21
+ /**
22
+ * Wrap a function that can throw, returning `Ok(fn())` if the function returns, `Err(error)` if it throws `error`.
23
+ * @param fn function that potentially throws
24
+ */
25
+ export declare function as_result<A extends any[], T>(fn: (...args: A) => T): (...args: A) => Result<T, any>;
26
+ /**
27
+ * Common method signatures for Result types.
28
+ */
29
+ interface ResultMethods<T, E> {
30
+ /**
31
+ * Returns `other` if the result is `Ok`, otherwise returns the first result's Err value.
32
+ * @param other result to return if the result is `Ok`.
33
+ */
34
+ and<U>(other: Result<U, E>): Result<U, E>;
35
+ /**
36
+ * Transforms `Result<T, E>` into an `Option<E>`, mapping `Ok(value)` to `None` discarding `value`
37
+ * and `Err(error)` to `Some(error)`.
38
+ */
39
+ err(): Option<E>;
40
+ /**
41
+ * Return the contained `Ok` value. Will throw a hard error with the specified message if called on `Err`.
42
+ * @param message custom message to throw if `None`
43
+ */
44
+ expect(message: string): T;
45
+ /**
46
+ * returns `true` if the result is `Ok`, `false` if `Err`.
47
+ */
48
+ is_ok(): this is Ok<T, E>;
49
+ /**
50
+ * returns `true` if the result is `Ok` and the value satisfies
51
+ * the given predicate, `false` otherwise.
52
+ */
53
+ is_ok_and(predicate: (value: T) => boolean): boolean;
54
+ /**
55
+ * returns `false` if the result is `Ok`, `true` if `Err`.
56
+ */
57
+ is_err(): this is Err<T, E>;
58
+ /**
59
+ * returns `true` if the result is `Err` and the error satisfies
60
+ * the given predicate, `false` otherwise.
61
+ */
62
+ is_err_and(predicate: (error: E) => boolean): boolean;
63
+ /**
64
+ * Maps a `Result<T, E>` into a `Result<U, E>`.
65
+ * Will return `Ok(fn(value))` if the result is `Ok`, or propagate `Err`.
66
+ * @param fn function to transform the inner value
67
+ */
68
+ map<U>(fn: (value: T) => U): Result<U, E>;
69
+ /**
70
+ * Maps a `Result<T, E>` into a `Result<T, F>`.
71
+ * Will propagate `Ok`, or return `Err(fn(error))` if the result is `Err`.
72
+ * @param fn function to transform the inner value
73
+ */
74
+ map_err<F>(fn: (error: E) => F): Result<T, F>;
75
+ /**
76
+ * Pattern-match on the result, running the `Ok` or `Err` function in the respective cases.
77
+ * @param matcher object containing an `Ok(value)` and `Err(error)` function to run
78
+ */
79
+ match<R>(matcher: {
80
+ Ok(value: T): R;
81
+ Err(error: E): R;
82
+ }): R;
83
+ /**
84
+ * Pattern-match on the result, running the former or latter function
85
+ * in the `Ok` and `Err` cases respectively.
86
+ *
87
+ * @param on_ok function to run if the result is `Ok(value)`
88
+ * @param on_err function to run if the option is `Err(error)`
89
+ */
90
+ match<R>(on_ok: (value: T) => R, on_err: (error: E) => R): R;
91
+ /**
92
+ * Transforms the `Result<T, E>` into an `Option<T>`, mapping `Ok(value)` to `Some(value)`
93
+ * and `Err(error)` to `None`, discarding `error`.
94
+ */
95
+ ok(): Option<T>;
96
+ /**
97
+ * Returns `other` if the result is `Err`, otherwise returns the first result's `Ok` value.
98
+ * @param other result to return if the result is `Err`.
99
+ */
100
+ or<F>(other: Result<T, F>): Result<T, F>;
101
+ /**
102
+ * Return the contained `Ok` value. Will throw a hard error if called on `Err`.
103
+ */
104
+ unwrap(): T;
105
+ /**
106
+ * Return the contained `Ok` value, or `default_value` if called on `Err`.
107
+ * @param default_value value to use if the result is `Err`
108
+ */
109
+ unwrap_or<T>(default_value: T): T;
110
+ /**
111
+ * Return the contained `Ok` value, or the result of `otherwise` if called on `Err`.
112
+ * @param otherwise function to use if the result is `Err`
113
+ */
114
+ unwrap_or_else<T>(otherwise: (error: E) => T): T;
115
+ }
116
+ /**
117
+ * A succesful result.
118
+ */
119
+ export interface Ok<T, E> extends ResultMethods<T, E> {
120
+ err(): None<E>;
121
+ is_err_and(predicate: (error: E) => boolean): false;
122
+ map<U>(fn: (value: T) => U): Ok<U, E>;
123
+ map_err<F>(fn: (error: E) => F): Ok<T, F>;
124
+ ok(): Some<T>;
125
+ or<F>(other: Result<T, F>): Ok<T, F>;
126
+ }
127
+ /**
128
+ * An expected, recoverable error.
129
+ */
130
+ export interface Err<T, E> extends ResultMethods<T, E> {
131
+ and<U>(other: Result<U, E>): Err<U, E>;
132
+ err(): Some<E>;
133
+ expect(message: string): never;
134
+ is_ok_and(predicate: (value: T) => boolean): false;
135
+ map<U>(fn: (value: T) => U): Err<U, E>;
136
+ map_err<F>(fn: (error: E) => F): Err<T, F>;
137
+ ok(): None<T>;
138
+ unwrap(): never;
139
+ }
140
+ /**
141
+ * @param value Inner value
142
+ */
143
+ export declare const Ok: <T, E>(value: T) => Ok<T, E>;
144
+ /**
145
+ * @param error Inner error
146
+ */
147
+ export declare const Err: <T, E>(error: E) => Err<T, E>;
148
+ export {};
package/lib/result.js ADDED
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Err = exports.Ok = void 0;
4
+ exports.as_result = as_result;
5
+ const option_1 = require("./option");
6
+ /**
7
+ * Wrap a function that can throw, returning `Ok(fn())` if the function returns, `Err(error)` if it throws `error`.
8
+ * @param fn function that potentially throws
9
+ */
10
+ function as_result(fn) {
11
+ return (...args) => {
12
+ try {
13
+ return (0, exports.Ok)(fn(...args));
14
+ }
15
+ catch (x) {
16
+ return (0, exports.Err)(x);
17
+ }
18
+ };
19
+ }
20
+ // Implementations
21
+ const nodeInspect = Symbol.for('nodejs.util.inspect.custom');
22
+ /**
23
+ * @param value Inner value
24
+ */
25
+ const Ok = (value) => ({
26
+ and(other) { return other; },
27
+ err() { return option_1.None; },
28
+ expect() { return value; },
29
+ is_err() { return false; },
30
+ is_err_and() { return false; },
31
+ is_ok() { return true; },
32
+ is_ok_and(predicate) { return predicate(value); },
33
+ map(fn) { return (0, exports.Ok)(fn(value)); },
34
+ map_err() { return this; },
35
+ match(matcher_or_ok) {
36
+ if ("Ok" in matcher_or_ok) {
37
+ return matcher_or_ok.Ok(value);
38
+ }
39
+ return matcher_or_ok(value);
40
+ },
41
+ ok() { return (0, option_1.Some)(value); },
42
+ or() { return this; },
43
+ unwrap() { return value; },
44
+ unwrap_or() { return value; },
45
+ unwrap_or_else() { return value; },
46
+ toString() { return `Ok(${value})`; },
47
+ [nodeInspect](_depth, inspectOptions, inspect) {
48
+ const green = inspectOptions.colors ? `\x1b[${inspect.colors.green[0]}m` : "";
49
+ const reset = inspectOptions.colors ? `\x1b[${inspect.colors.reset[0]}m` : "";
50
+ return `${green}Ok${reset}(${inspect(value, inspectOptions)})`;
51
+ }
52
+ });
53
+ exports.Ok = Ok;
54
+ /**
55
+ * @param error Inner error
56
+ */
57
+ const Err = (error) => ({
58
+ and() { return this; },
59
+ err() { return (0, option_1.Some)(error); },
60
+ expect(message) { throw Error(`${message}: ${error}`); },
61
+ is_err() { return true; },
62
+ is_err_and(predicate) { return predicate(error); },
63
+ is_ok() { return false; },
64
+ is_ok_and() { return false; },
65
+ map() { return this; },
66
+ map_err(fn) { return (0, exports.Err)(fn(error)); },
67
+ match(matcher_or_ok, err) {
68
+ if ("Err" in matcher_or_ok) {
69
+ return matcher_or_ok.Err(error);
70
+ }
71
+ return err(error);
72
+ },
73
+ ok() { return option_1.None; },
74
+ or(other) { return other; },
75
+ unwrap() { throw Error(`Called unwrap on an Err value: ${error}`); },
76
+ unwrap_or(default_value) { return default_value; },
77
+ unwrap_or_else(otherwise) { return otherwise(error); },
78
+ toString() { return `Err(${error})`; },
79
+ [nodeInspect](_depth, inspectOptions, inspect) {
80
+ const red = inspectOptions.colors ? `\x1b[${inspect.colors.red[0]}m` : "";
81
+ const reset = inspectOptions.colors ? `\x1b[${inspect.colors.reset[0]}m` : "";
82
+ return `${red}Err${reset}(${inspect(error, inspectOptions)})`;
83
+ }
84
+ });
85
+ exports.Err = Err;
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "rstypes",
3
+ "version": "1.0.0",
4
+ "description": "Type-safe implementation of Rust's Option and Result types",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/p2js/rstypes"
8
+ },
9
+ "homepage": "https://github.com/p2js/rstypes",
10
+ "exports": {
11
+ "./option": {
12
+ "default": "./lib/option.js",
13
+ "types": "./lib/option.d.ts"
14
+ },
15
+ "./result": {
16
+ "default": "./lib/result.js",
17
+ "types": "./lib/result.d.ts"
18
+ }
19
+ },
20
+ "files": [
21
+ "lib",
22
+ "readme.md"
23
+ ],
24
+ "keywords": [
25
+ "type-safe",
26
+ "typescript",
27
+ "types",
28
+ "option",
29
+ "result",
30
+ "rust",
31
+ "rust-types",
32
+ "error-handling"
33
+ ],
34
+ "author": "Alfio (https://github.com/p2js)",
35
+ "license": "ISC",
36
+ "scripts": {
37
+ "build": "tsc"
38
+ }
39
+ }
package/readme.md ADDED
@@ -0,0 +1,218 @@
1
+ # RSTypes
2
+
3
+ Type-safe implementation of lightweight Option and Result types in TypeScript (and JavaScript).
4
+
5
+ ```ts
6
+ import { Option, Some, None } from "rstypes/option";
7
+
8
+ function index_in_array<T>(array: T[], search: T): Option<number> {
9
+ let index = array.indexOf(search);
10
+
11
+ if(index == -1) {
12
+ return None;
13
+ } else {
14
+ return Some(index);
15
+ }
16
+ }
17
+
18
+ let idx = index_in_array([1, 2, 3], 2);
19
+
20
+ idx.match({
21
+ Some(value) { console.log("Found at index: ", value) },
22
+ None() { console.log("Could not find in array") }
23
+ })
24
+ ```
25
+ ```ts
26
+ import { Result, Ok, Err } from "rstypes/result"; // ESM
27
+ const { Result, Ok, Err } = require("rstypes/result"); // CommonJS
28
+
29
+ function parse_int(str: string): Result<number, string> {
30
+ let maybe_number = parseInt(str);
31
+ if(isNaN(maybe_number)) return Err("Invalid string");
32
+ return Ok(maybe_number);
33
+ }
34
+
35
+ let result = parse_int("333");
36
+ result.match({
37
+ Ok(num) { console.log("Parsed number: ", num) },
38
+ Err(msg) { console.log("Error parsing: ", msg) }
39
+ });
40
+ ```
41
+
42
+ ## Table of contents
43
+
44
+ - [Usage](#usage)
45
+ - [Basic type information](#basic-type-information)
46
+ - [Handling Option and Result values](#handling-option-and-result-values)
47
+ - [match](#match)
48
+ - [unwrap, expect](#unwrap-expect)
49
+ - [unwrap_or, unwrap_or_else](#unwrap_or-unwrap_or_else)
50
+ - [is_ok, is_err](#is_ok-is_err)
51
+ - [is_ok_and, is_err_and](#is_ok_and-is_err_and)
52
+ - [map, map_err](#map-map_err)
53
+ - [ok, err](#ok-err)
54
+ - [and, or](#and-or)
55
+ - [Converting standard functions](#converting-standard-functions)
56
+ - [Developer considerations](#developer-considerations)
57
+
58
+ ## Usage
59
+
60
+ You can install rstypes on [npm](https://npmjs.com/package/rstypes):
61
+
62
+ ```sh
63
+ npm install rstypes
64
+ ```
65
+
66
+ ### Basic type information
67
+
68
+ Use `Option<T>` to represent an optional value, for example:
69
+ - An explicit optional parameter in a function.
70
+ - An object that may or may not have a value in its field, but should always have that field.
71
+ - A function that may or may not return a value.
72
+
73
+ Use `Result<T, E>` to represent either a successful return value or an error that is expected and recoverable, for example:
74
+ - A parsing function that can fail with malformed input.
75
+ - A function that can error based on external state.
76
+ - A function that can fail in multiple ways that should be handled separately.
77
+
78
+
79
+ These types give you a type-safe alternative to returning `null` or `undefined` and throwing exceptions, in ways that can be handled more explicitly and are immediately clear from the function signature.
80
+
81
+ ### Handling Option and Result values
82
+
83
+ `Option` and `Result` values can be handled almost identically (The examples below will focus on `Result` but will clarify differences with handling `Option`s).
84
+
85
+ Consider an example `Result` variable:
86
+
87
+ ```ts
88
+ let res: Result<number, string> = /* ... */
89
+ ```
90
+
91
+ Where `number` is the `Ok` type and `string` is the `Err` type.
92
+
93
+ #### match
94
+
95
+ Matching on values is exhaustive, and can be done using a more verbose Rust-like syntax using an object, or simply two arrow functions for conciseness. This is considered the default way to handle values for its expressiveness and flexibility.
96
+
97
+ ```ts
98
+ res.match({
99
+ Ok(value) { /* do something with value */ },
100
+ Err(error) { console.error(error); }
101
+ })
102
+
103
+ let x = res.match(
104
+ value => 2 * value,
105
+ error => { console.error("There was an error"); return 0; }
106
+ );
107
+ ```
108
+
109
+ > N.B. `Option` values match on the two functions `Some(value)` and `None()` instead, where the `None` case takes no arguments.
110
+
111
+ #### unwrap, expect
112
+
113
+ These two methods should **only** be used when you are sure that the value cannot be `Err`/`None` and just want immediate access to the inner value (ie. when the error case would violate a fundamental assumption of the program). These functions will hard error if called on `Err`/`None`, with `unwrap` throwing a generic error and `expect` throwing an error with the specified message:
114
+
115
+ ```ts
116
+ let x: number = res.unwrap();
117
+ let y: number = res.expect("Should never error with the given inputs");
118
+ ```
119
+
120
+ #### unwrap_or, unwrap_or_else
121
+
122
+ These two methods should be used when you don't care to handle the error case and want suitable default behaviour instead.
123
+
124
+ ```ts
125
+ let x: number = res.unwrap_or(0);
126
+ let y: number = res.unwrap_or_else(() => Math.random()); // the function can also depend on the error value!
127
+ ```
128
+
129
+ #### is_ok, is_err
130
+
131
+ These two methods return true or false when the `Result` value is the appropriate variant. They can be used for more traditional/non-exhaustive handling, and TypeScript will automatically narrow the type to the respective variant within their blocks.
132
+
133
+ ```ts
134
+ if(res.is_ok()) {
135
+ let x = res.unwrap(); // Guaranteed not to fail
136
+ // ...
137
+ } else {
138
+ console.log("There was some error");
139
+ }
140
+ ```
141
+ > N.B. `Option` values have analogous predicates `is_some` and `is_none`.
142
+
143
+ ### is_ok_and, is_err_and
144
+
145
+ These two methods return true when the result value is of the appropriate variant and a given predicate evaluates to `true` with the inner value, returning false otherwise. They can be used to check for a given property of contained values.
146
+
147
+ ```ts
148
+ if(res.is_ok_and(n => n % 2 == 0)) {
149
+ let even = res.unwrap();
150
+ //...
151
+ }
152
+ ```
153
+ > N.B. `Option` values have equivalent `is_some_and` and `is_none_or`, with the latter returning true if the option is `None`, or `Some(value)` with the predicate being true for `value`.
154
+
155
+ #### map, map_err
156
+
157
+ These two methods can convert between `Result` values with a different `Ok` type and `Err` type respectively, propagating the alternate value otherwise. They can be used to perform transformations conditionally.
158
+
159
+ ```ts
160
+ let s: Result<string, string> = res.map((n) => `number ${n}`);
161
+ let e: Result<number, Error> = res.map_err((e) => Error(e));
162
+ ```
163
+ > N.B. `Option` values only have `map` to translate between `Option<T>` and `Option<U>`.
164
+
165
+ ### ok, err
166
+
167
+ These two methods convert a `Result<T,E>` into an `Option<T>` and `Option<E>` respectively, returning `Some(value)` if the variant matches the method called and `None` otherwise. They can be used to translate between the two types as needed.
168
+
169
+ ```ts
170
+ let n: Option<number> = res.ok();
171
+ let s: Option<number> = res.err();
172
+ ```
173
+ > N.B. `Option` values have an equivalent `ok_or(error)` method to translate `Some(value)` into `Ok(value)` and `None` into `Err(error)`.
174
+
175
+ ### and, or
176
+
177
+ These two methods can be used to perform logic on `Result` values, evaluating to the alternative given if the first result is `Ok` or `Err` respectively, or itself otherwise.
178
+
179
+ ```ts
180
+ let res2: Result<number, string> = Err("something");
181
+
182
+ let or = res2.or(res) // or == res
183
+ let and = res2.and(res); // or == Err("something")
184
+ ```
185
+ > N.B. `Option` values also have an `xor` method that performs similar logic, evaluating to `None` when both options are `Some` or `None` and the only `Some(value)` otherwise.
186
+
187
+ ### Converting standard functions
188
+
189
+ This library also offers two wrappers to convert other JavaScript functions into these patterns:
190
+
191
+ - `as_result` takes a function that can throw and outputs a function that returns a `Result`, with `Ok` if it returned and `Err` if it threw.
192
+
193
+ ```ts
194
+ import { as_result } from "rstypes/result";
195
+ let parse_json = as_result(JSON.parse);
196
+
197
+ let parsed: Result<any, SyntaxError> = parse_json("{}"); // parsed = {}
198
+ let error: Result<any, SyntaxError> = parse_json("abcd"); // error = Err(SyntaxError(...))
199
+
200
+ ```
201
+
202
+ - `as_option` takes a function that can return `NaN`, `null` or `undefined` and outputs a function that returns an `Option`, with `None` if it returned one of those values or `Some` otherwise.
203
+
204
+ ```ts
205
+ import { as_option } from "rstypes/option";
206
+ let sqrt = as_option(Math.sqrt);
207
+
208
+ let y1: Option<number> = sqrt(1); // y1 = Some(1)
209
+ let y2: Option<number> = sqrt(-1); // y2 = None
210
+ ```
211
+
212
+ ### Developer considerations
213
+
214
+ For additional type safety (such as not being able to call `unwrap` on directly instantiated `Err` values), the outputs of `Ok(x: T)` and `Err(e: E)` are not considered to be values of `Result<T, E>` but rather of their own individual types: `Ok<T, unknown>` and `Err<unknown, E>`. This is also due to the impossibility of inferring a `T` type from a construction of `Err<unknown, E>` and vice versa, resulting in confusing type signatures when returning both from functions.
215
+
216
+ Therefore, for best developer experience, take care to use explicit `Result<T, E>` type annotations where possible.
217
+
218
+ > N.B. Holds analogously for `Some` and `None`.