@madkarma/result 1.0.2 → 2.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.
package/README.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  Rust's Result type, for TypeScript.
4
4
 
5
+ Inspired by [this video](https://www.youtube.com/watch?v=ovnyeq-Xxrc) by Web Dev Simplified and [vultix/ts-results](https://github.com/vultix/ts-results).
6
+
7
+ This library mimics the Rust `Result` enum and includes its chainable methods adapted for TypeScript. For full documentation on the available methods, please refer to the [official Rust Result documentation](https://doc.rust-lang.org/std/result/enum.Result.html) (or read the JSDocs directly in your editor).
8
+
5
9
  ## Installation
6
10
 
7
11
  ```bash
@@ -19,40 +23,49 @@ yarn add @madkarma/result
19
23
  ```typescript
20
24
  import { Ok, Err } from '@madkarma/result';
21
25
 
22
- const getUser = (id: number) => {
23
- if (typeof id !== 'number')
24
- return Err({ code: 'NOT_A_NUMBER', message: 'ID must be a number' });
26
+ const parseUserId = (id: string) => {
27
+ const parsed = parseInt(id, 10);
28
+ if (isNaN(parsed))
29
+ return Err({
30
+ code: 'INVALID_INPUT',
31
+ message: 'ID must be a valid number'
32
+ });
25
33
 
26
- if (id < 0)
34
+ if (parsed <= 0)
27
35
  return Err({ code: 'INVALID_ID', message: 'ID must be positive' });
28
36
 
29
- if (id === 0) return Err({ code: 'NOT_FOUND', message: 'User not found' });
37
+ return Ok(parsed);
38
+ };
39
+
40
+ const fetchUser = (id: number) => {
41
+ if (id === 13) return Err({ code: 'NOT_FOUND', message: 'User not found' });
30
42
 
31
- return Ok({ id, name: 'Alice' });
43
+ return Ok({ id, name: 'Alice', role: 'admin' });
32
44
  };
33
45
 
34
- const [user, error] = getUser(10);
46
+ // Processing an input by chaining methods
47
+ const { value: user, error } = parseUserId('10')
48
+ .map((id) => id + 3) // Transform the Ok value (10 -> 13)
49
+ .andThen(fetchUser); // Chain operations that return another Result
35
50
 
36
- if (error)
51
+ if (error) {
37
52
  switch (error.code) {
38
- case 'NOT_A_NUMBER':
39
- console.error(error.message);
40
- break;
53
+ case 'INVALID_INPUT':
41
54
  case 'INVALID_ID':
42
- console.error(error.message);
55
+ console.error(`Validation Error: ${error.message}`);
43
56
  break;
44
57
  case 'NOT_FOUND':
45
- console.error(error.message);
58
+ console.error(`Database Error: ${error.message}`);
46
59
  break;
47
60
  }
48
- else console.log(`Hello, ${user.name}!`);
61
+ } else {
62
+ console.log(`Welcome, ${user.role} ${user.name}!`);
63
+ }
49
64
  ```
50
65
 
51
- ### How this differs from Rust
52
-
53
- Instead of Rust's `match` expressions, check `[value, error]` directly and use a JavaScript `switch` on `error.code` to emulate pattern matching.
66
+ ## How this differs from Rust
54
67
 
55
- This library is essentially a type-safe helper for TypeScript developers. It does **not** include any of the chainable methods found in the actual Rust `Result` type. Its sole purpose is to enforce explicit error handling through control flow.
68
+ Instead of Rust's `match` expressions, check `{ value, error }` directly and use a `switch` on `error.code` to emulate pattern matching.
56
69
 
57
70
  ## Contributing
58
71
 
package/dist/index.d.ts CHANGED
@@ -1,58 +1,2 @@
1
- /**
2
- * `Result<T, E>` is the type used for returning and propagating errors.
3
- *
4
- * It is a type with the parameters, `Ok(T)`, representing success and containing a value,
5
- * and `Err(E)`, representing error and containing an error value.
6
- *
7
- * Functions return `Result` whenever errors are expected and recoverable.
8
- *
9
- * The error type `E` must be an object that contains a `code` property of type `string`.
10
- *
11
- * @example
12
- * ```typescript
13
- * const divide = (a: number, b: number) => {
14
- * if (b === 0) return Err({ code: 'DIVIDE_BY_ZERO' });
15
- * return Ok(a / b);
16
- * }
17
- *
18
- * const [value, error] = divide(10, 2);
19
- * if (error) console.error(error.code);
20
- * else console.log(value);
21
- * ```
22
- *
23
- * @see https://www.youtube.com/watch?v=ovnyeq-Xxrc
24
- * @template T - Contains the success value.
25
- * @template E - Contains the error value. Must have a `code` property of type `string`.
26
- */
27
- export type Result<T, E extends {
28
- code: string;
29
- }> = [T, null] | [null, E];
30
- /**
31
- * Contains the success value.
32
- *
33
- * @example
34
- * ```typescript
35
- * const result = Ok(42);
36
- * ```
37
- *
38
- * @see https://www.youtube.com/watch?v=ovnyeq-Xxrc
39
- * @param value - The value to wrap in a successful result.
40
- * @returns A `Result` representing a successful outcome.
41
- */
42
- export declare const Ok: <T>(value: T) => Result<T, never>;
43
- /**
44
- * Contains the error value.
45
- *
46
- * @example
47
- * ```typescript
48
- * const result = Err({ code: 'NOT_FOUND' });
49
- * ```
50
- *
51
- * @see https://www.youtube.com/watch?v=ovnyeq-Xxrc
52
- * @param error - The error to wrap in a failed result. Must have a `code` property of type `string`.
53
- * @returns A `Result` representing a failed outcome.
54
- */
55
- export declare const Err: <const C extends string, E extends {
56
- code: C;
57
- }>(error: E) => Result<never, E>;
1
+ export * from './result';
58
2
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,MAAM,MAAM,CAAC,CAAC,EAAE,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;AAE1E;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,EAAE,GAAI,CAAC,EAAE,OAAO,CAAC,KAAG,MAAM,CAAC,CAAC,EAAE,KAAK,CAAkB,CAAC;AAEnE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,GAAG,GAAI,KAAK,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS;IAAE,IAAI,EAAE,CAAC,CAAA;CAAE,EAC7D,OAAO,CAAC,KACT,MAAM,CAAC,KAAK,EAAE,CAAC,CAOjB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC"}
package/dist/index.js CHANGED
@@ -1,31 +1,2 @@
1
- /**
2
- * Contains the success value.
3
- *
4
- * @example
5
- * ```typescript
6
- * const result = Ok(42);
7
- * ```
8
- *
9
- * @see https://www.youtube.com/watch?v=ovnyeq-Xxrc
10
- * @param value - The value to wrap in a successful result.
11
- * @returns A `Result` representing a successful outcome.
12
- */
13
- export const Ok = (value) => [value, null];
14
- /**
15
- * Contains the error value.
16
- *
17
- * @example
18
- * ```typescript
19
- * const result = Err({ code: 'NOT_FOUND' });
20
- * ```
21
- *
22
- * @see https://www.youtube.com/watch?v=ovnyeq-Xxrc
23
- * @param error - The error to wrap in a failed result. Must have a `code` property of type `string`.
24
- * @returns A `Result` representing a failed outcome.
25
- */
26
- export const Err = (error) => {
27
- if (typeof error.code !== 'string')
28
- throw new TypeError('Error object must have a code property of type string');
29
- return [null, error];
30
- };
1
+ export * from './result';
31
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA4BA;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,EAAE,GAAG,CAAI,KAAQ,EAAoB,EAAE,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AAEnE;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,GAAG,GAAG,CACf,KAAQ,EACQ,EAAE;IAClB,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ;QAC9B,MAAM,IAAI,SAAS,CACf,uDAAuD,CAC1D,CAAC;IAEN,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AACzB,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC"}
@@ -0,0 +1,196 @@
1
+ /**
2
+ * The base interface for all errors returned by a `Result`.
3
+ * It requires a `code` property which can be used to identify the error type.
4
+ */
5
+ export interface ResultError {
6
+ code: string;
7
+ }
8
+ /**
9
+ * Represents a successful `Result` containing a value of type `T`.
10
+ */
11
+ export type OkResult<T, E extends ResultError> = {
12
+ readonly value: T;
13
+ readonly error: null;
14
+ } & ResultMethods<T, E>;
15
+ /**
16
+ * Represents a failed `Result` containing an error of type `E`.
17
+ */
18
+ export type ErrResult<T, E extends ResultError> = {
19
+ readonly value: null;
20
+ readonly error: E;
21
+ } & ResultMethods<T, E>;
22
+ /**
23
+ * `Result<T, E>` is the type used for returning and propagating errors.
24
+ *
25
+ * It is a type with the parameters, `Ok(T)`, representing success and containing a value,
26
+ * and `Err(E)`, representing error and containing an error value.
27
+ *
28
+ * Functions return `Result` whenever errors are expected and recoverable.
29
+ *
30
+ * The error type `E` must extend `ResultError` which contains a `code` property of type `string`.
31
+ *
32
+ * @example
33
+ * ```typescript
34
+ * const divide = (a: number, b: number) => {
35
+ * if (b === 0) return Err({ code: 'DIVIDE_BY_ZERO' });
36
+ * return Ok(a / b);
37
+ * }
38
+ *
39
+ * const { value, error } = divide(10, 2);
40
+ * if (error) console.error(error.code);
41
+ * else console.log(value);
42
+ * ```
43
+ *
44
+ * @see https://www.youtube.com/watch?v=ovnyeq-Xxrc
45
+ * @template T - Contains the success value.
46
+ * @template E - Contains the error value. Must have a `code` property of type `string`.
47
+ */
48
+ export type Result<T, E extends ResultError> = OkResult<T, E> | ErrResult<T, E>;
49
+ interface ResultMethods<T, E extends ResultError> {
50
+ /**
51
+ * Returns `true` if the result is `Ok`.
52
+ */
53
+ isOk(): this is OkResult<T, E>;
54
+ /**
55
+ * Returns `true` if the result is `Ok` and the value inside of it matches a predicate.
56
+ */
57
+ isOkAnd(fn: (val: T) => boolean): this is OkResult<T, E>;
58
+ /**
59
+ * Returns `true` if the result is `Err`.
60
+ */
61
+ isErr(): this is ErrResult<T, E>;
62
+ /**
63
+ * Returns `true` if the result is `Err` and the value inside of it matches a predicate.
64
+ */
65
+ isErrAnd(fn: (err: E) => boolean): this is ErrResult<T, E>;
66
+ /**
67
+ * Maps a `Result<T, E>` to `Result<U, E>` by applying a function to a contained `Ok` value, leaving an `Err` value untouched.
68
+ *
69
+ * This function can be used to compose the results of two functions.
70
+ */
71
+ map<U>(fn: (val: T) => U): Result<U, E>;
72
+ /**
73
+ * Returns the provided default (if `Err`), or applies a function to the contained value (if `Ok`).
74
+ *
75
+ * 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.
76
+ */
77
+ mapOr<U>(fallback: U, fn: (val: T) => U): U;
78
+ /**
79
+ * Maps a `Result<T, E>` to `U` by applying fallback function `fallbackFn` to a contained `Err` value, or function `fn` to a contained `Ok` value.
80
+ *
81
+ * This function can be used to unpack a successful result while handling an error.
82
+ */
83
+ mapOrElse<U>(fallbackFn: (err: E) => U, fn: (val: T) => U): U;
84
+ /**
85
+ * Maps a `Result<T, E>` to `Result<T, F>` by applying a function to a contained `Err` value, leaving an `Ok` value untouched.
86
+ *
87
+ * This function can be used to pass through a successful result while handling an error.
88
+ */
89
+ mapErr<F extends ResultError>(fn: (err: E) => F): Result<T, F>;
90
+ /**
91
+ * Calls a function with a reference to the contained value if `Ok`.
92
+ *
93
+ * Returns the original result.
94
+ */
95
+ inspect(fn: (val: T) => void): Result<T, E>;
96
+ /**
97
+ * Calls a function with a reference to the contained value if `Err`.
98
+ *
99
+ * Returns the original result.
100
+ */
101
+ inspectErr(fn: (err: E) => void): Result<T, E>;
102
+ /**
103
+ * Returns an iterator over the possibly contained value.
104
+ *
105
+ * The iterator yields one value if the result is `Result::Ok`, otherwise none.
106
+ */
107
+ iter(): Iterable<T>;
108
+ /**
109
+ * Returns the contained `Ok` value, consuming the `self` value.
110
+ *
111
+ * @throws Throws if the value is an `Err`, with an error message including the passed message, and the content of the `Err`.
112
+ */
113
+ expect(msg: string): T;
114
+ /**
115
+ * Returns the contained `Ok` value, consuming the `self` value.
116
+ *
117
+ * @throws Throws if the value is an `Err`, with an error message provided by the `Err`'s value.
118
+ */
119
+ unwrap(): T;
120
+ /**
121
+ * Returns the contained `Err` value, consuming the `self` value.
122
+ *
123
+ * @throws Throws if the value is an `Ok`, with an error message including the passed message, and the content of the `Ok`.
124
+ */
125
+ expectErr(msg: string): E;
126
+ /**
127
+ * Returns the contained `Err` value, consuming the `self` value.
128
+ *
129
+ * @throws Throws if the value is an `Ok`, with a custom error message provided by the `Ok`'s value.
130
+ */
131
+ unwrapErr(): E;
132
+ /**
133
+ * Returns `res` if the result is `Ok`, otherwise returns the `Err` value of `self`.
134
+ *
135
+ * 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.
136
+ */
137
+ and<U, E2 extends ResultError>(res: Result<U, E2>): Result<U, E | E2>;
138
+ /**
139
+ * Calls `fn` if the result is `Ok`, otherwise returns the `Err` value of `self`.
140
+ *
141
+ * This function can be used for control flow based on `Result` values.
142
+ */
143
+ andThen<U, F extends ResultError>(fn: (val: T) => Result<U, F>): Result<U, E | F>;
144
+ /**
145
+ * Returns `res` if the result is `Err`, otherwise returns the `Ok` value of `self`.
146
+ *
147
+ * 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.
148
+ */
149
+ or<T2, F extends ResultError>(res: Result<T2, F>): Result<T | T2, F>;
150
+ /**
151
+ * Calls `fn` if the result is `Err`, otherwise returns the `Ok` value of `self`.
152
+ *
153
+ * This function can be used for control flow based on result values.
154
+ */
155
+ orElse<T2, F extends ResultError>(fn: (err: E) => Result<T2, F>): Result<T | T2, F>;
156
+ /**
157
+ * Returns the contained `Ok` value or a provided default.
158
+ *
159
+ * 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.
160
+ */
161
+ unwrapOr<T2>(fallback: T2): T | T2;
162
+ /**
163
+ * Returns the contained `Ok` value or computes it from a closure.
164
+ */
165
+ unwrapOrElse<T2>(fn: (err: E) => T2): T | T2;
166
+ }
167
+ /**
168
+ * Contains the success value.
169
+ *
170
+ * @example
171
+ * ```typescript
172
+ * const { value } = Ok(42);
173
+ * ```
174
+ *
175
+ * @see https://www.youtube.com/watch?v=ovnyeq-Xxrc
176
+ * @param value - The value to wrap in a successful result.
177
+ * @returns A `Result` representing a successful outcome.
178
+ */
179
+ export declare const Ok: <T, E extends ResultError = never>(value: T) => Result<T, E>;
180
+ /**
181
+ * Contains the error value.
182
+ *
183
+ * @example
184
+ * ```typescript
185
+ * const { error } = Err({ code: 'NOT_FOUND' });
186
+ * ```
187
+ *
188
+ * @see https://www.youtube.com/watch?v=ovnyeq-Xxrc
189
+ * @param error - The error to wrap in a failed result. Must have a `code` property of type `string`.
190
+ * @returns A `Result` representing a failed outcome.
191
+ */
192
+ export declare const Err: <const C extends string, E extends ResultError & {
193
+ code: C;
194
+ }>(error: E) => Result<never, E>;
195
+ export {};
196
+ //# sourceMappingURL=result.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result.d.ts","sourceRoot":"","sources":["../src/result.ts"],"names":[],"mappings":"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"}
package/dist/result.js ADDED
@@ -0,0 +1,145 @@
1
+ class ResultImpl {
2
+ // will error at runtime if trying to access # fields
3
+ #value;
4
+ #error;
5
+ constructor(value, error) {
6
+ this.#value = value;
7
+ this.#error = error;
8
+ }
9
+ // will prevent mutation at runtime
10
+ get value() {
11
+ return this.#value;
12
+ }
13
+ // will prevent mutation at runtime
14
+ get error() {
15
+ return this.#error;
16
+ }
17
+ isOk() {
18
+ return this.error === null;
19
+ }
20
+ isOkAnd(fn) {
21
+ return this.isOk() && fn(this.value);
22
+ }
23
+ isErr() {
24
+ return this.error !== null;
25
+ }
26
+ isErrAnd(fn) {
27
+ return this.isErr() && fn(this.error);
28
+ }
29
+ map(fn) {
30
+ if (this.isErr()) {
31
+ return new ResultImpl(null, this.error);
32
+ }
33
+ return new ResultImpl(fn(this.value), null);
34
+ }
35
+ mapOr(fallback, fn) {
36
+ if (this.isErr())
37
+ return fallback;
38
+ return fn(this.value);
39
+ }
40
+ mapOrElse(fallbackFn, fn) {
41
+ if (this.isErr())
42
+ return fallbackFn(this.error);
43
+ return fn(this.value);
44
+ }
45
+ mapErr(fn) {
46
+ if (this.isErr())
47
+ return new ResultImpl(null, fn(this.error));
48
+ return new ResultImpl(this.value, null);
49
+ }
50
+ inspect(fn) {
51
+ if (this.isOk())
52
+ fn(this.value);
53
+ return this;
54
+ }
55
+ inspectErr(fn) {
56
+ if (this.isErr())
57
+ fn(this.error);
58
+ return this;
59
+ }
60
+ *iter() {
61
+ if (this.isOk())
62
+ yield this.value;
63
+ }
64
+ expect(msg) {
65
+ if (this.isErr())
66
+ throw new Error(msg);
67
+ return this.value;
68
+ }
69
+ unwrap() {
70
+ if (this.error !== null)
71
+ throw this.error;
72
+ return this.value;
73
+ }
74
+ expectErr(msg) {
75
+ if (this.isOk())
76
+ throw new Error(msg);
77
+ return this.error;
78
+ }
79
+ unwrapErr() {
80
+ if (this.isOk())
81
+ throw new Error(String(this.value));
82
+ return this.error;
83
+ }
84
+ and(res) {
85
+ if (this.isOk())
86
+ return res;
87
+ return new ResultImpl(null, this.error);
88
+ }
89
+ andThen(fn) {
90
+ if (this.isOk())
91
+ return fn(this.value);
92
+ return new ResultImpl(null, this.error);
93
+ }
94
+ or(res) {
95
+ if (this.isErr())
96
+ return res;
97
+ return new ResultImpl(this.value, null);
98
+ }
99
+ orElse(fn) {
100
+ if (this.isErr())
101
+ return fn(this.error);
102
+ return new ResultImpl(this.value, null);
103
+ }
104
+ unwrapOr(fallback) {
105
+ if (this.isErr())
106
+ return fallback;
107
+ return this.value;
108
+ }
109
+ unwrapOrElse(fn) {
110
+ if (this.isErr())
111
+ return fn(this.error);
112
+ return this.value;
113
+ }
114
+ }
115
+ /**
116
+ * Contains the success value.
117
+ *
118
+ * @example
119
+ * ```typescript
120
+ * const { value } = Ok(42);
121
+ * ```
122
+ *
123
+ * @see https://www.youtube.com/watch?v=ovnyeq-Xxrc
124
+ * @param value - The value to wrap in a successful result.
125
+ * @returns A `Result` representing a successful outcome.
126
+ */
127
+ export const Ok = (value) => {
128
+ return new ResultImpl(value, null);
129
+ };
130
+ /**
131
+ * Contains the error value.
132
+ *
133
+ * @example
134
+ * ```typescript
135
+ * const { error } = Err({ code: 'NOT_FOUND' });
136
+ * ```
137
+ *
138
+ * @see https://www.youtube.com/watch?v=ovnyeq-Xxrc
139
+ * @param error - The error to wrap in a failed result. Must have a `code` property of type `string`.
140
+ * @returns A `Result` representing a failed outcome.
141
+ */
142
+ export const Err = (error) => {
143
+ return new ResultImpl(null, error);
144
+ };
145
+ //# sourceMappingURL=result.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result.js","sourceRoot":"","sources":["../src/result.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@madkarma/result",
3
- "version": "1.0.2",
3
+ "version": "2.0.0",
4
4
  "description": "Rust's Result type, for TypeScript",
5
5
  "devDependencies": {
6
6
  "prettier": "3.8.3",
7
- "typescript": "^6.0.3"
7
+ "typescript": "^6.0.3",
8
+ "vitest": "^4.1.6"
8
9
  },
9
10
  "type": "module",
10
11
  "exports": {
@@ -18,6 +19,8 @@
18
19
  "dist"
19
20
  ],
20
21
  "scripts": {
22
+ "test:dev": "vitest watch",
23
+ "test": "vitest run",
21
24
  "build": "tsc",
22
25
  "dev": "tsc --watch",
23
26
  "format": "prettier --write --ignore-unknown .",