@mkvlrn/result 5.0.8 → 6.0.1

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,7 +2,7 @@
2
2
 
3
3
  Dead simple Result pattern for TypeScript.
4
4
 
5
- No `.map()`, no `.flatMap()`, no `.andThen()`, no `.orElse()`, no `.unwrap()`, no monadic gymnastics. Just a type, two functions, and TypeScript doing what TypeScript already does well.
5
+ No `.map()`, no `.flatMap()`, no `.andThen()`, no `.orElse()`, no `.unwrap()`, no monadic gymnastics. Just two types with two functions. Then TypeScript does its thing.
6
6
 
7
7
  [![npm](https://img.shields.io/npm/v/@mkvlrn/result)](https://www.npmjs.com/package/@mkvlrn/result)
8
8
 
@@ -10,9 +10,9 @@ No `.map()`, no `.flatMap()`, no `.andThen()`, no `.orElse()`, no `.unwrap()`, n
10
10
 
11
11
  There are dozens of Result libraries for TypeScript. Nearly all of them bolt on method chaining, transformation pipelines, and functional programming utilities that turn a simple concept into an entire paradigm.
12
12
 
13
- This package does **one thing**: gives you a type-safe `Result<T, E>` discriminated union with `ok()` and `err()` constructors. You use `if/else` to handle it. TypeScript narrows the type for you. That's the whole API.
13
+ This package does **one thing**: gives you a type-safe `ResultSync<T, E>` or `ResultAsync<T, E>` discriminated union with `ok()` and `err()` constructors. You use `if/else` to handle it. TypeScript narrows the type for you. That's the whole API.
14
14
 
15
- **The entire implementation is ~35 lines. Zero runtime dependencies. Four exports.**
15
+ **The entire implementation is ~35 lines. Zero runtime dependencies. Two exports.**
16
16
 
17
17
  If you need `.map().flatMap().andThen().orElse().unwrapOr()` chains, use [neverthrow](https://github.com/supermacro/neverthrow) or [ts-results](https://github.com/vultix/ts-results). They're good libraries. This isn't that.
18
18
 
@@ -24,61 +24,59 @@ pnpm add @mkvlrn/result
24
24
 
25
25
  ## API
26
26
 
27
- | Export | What it does |
28
- | ------------------- | -------------------------------------------- |
29
- | `Result<T, E>` | Union type representing success or failure |
30
- | `AsyncResult<T, E>` | `Promise<Result<T, E>>` for async operations |
31
- | `ok(value)` | Creates a success result |
32
- | `err(error)` | Creates an error result |
27
+ | Export | What it does |
28
+ | ------------------- | ------------------------------------------- |
29
+ | `ResultSync<T, E>` | Sync Result type and `{ ok, err }` helpers |
30
+ | `ResultAsync<T, E>` | Async Result type and `{ ok, err }` helpers |
33
31
 
34
32
  That's it. That's the whole thing.
35
33
 
36
34
  ## Usage
37
35
 
38
36
  ```typescript
39
- import { type Result, type AsyncResult, ok, err } from "@mkvlrn/result";
37
+ import { ResultSync, ResultAsync } from "@mkvlrn/result";
40
38
  ```
41
39
 
42
40
  ### Create results, check results
43
41
 
44
42
  ```typescript
45
- function divide(a: number, b: number): Result<number, Error> {
43
+ function divide(a: number, b: number): ResultSync<number, Error> {
46
44
  if (b === 0) {
47
- return err(new Error("Division by zero"));
45
+ return ResultSync.err(new Error("Division by zero"));
48
46
  }
49
- return ok(a / b);
50
- }
51
47
 
52
- const result = divide(10, 2);
53
- if (result.isOk) {
54
- console.log(result.value); // number - TypeScript knows
48
+ return ResultSync.ok(a / b);
55
49
  }
56
50
 
51
+ const result = divide(10, 2);
57
52
  if (result.isError) {
58
53
  console.log(result.error.message); // Error - TypeScript knows
54
+ } else {
55
+ console.log(result.value); // number - TypeScript knows
59
56
  }
60
57
  ```
61
58
 
62
- No `.unwrap()`. No `.expect()`. Just an `if` statement and the compiler handles the rest.
59
+ No `.unwrap()`, no `.expect()`, no other dozens of functions. You just use an `if` statement and the compiler handles the rest.
63
60
 
64
61
  ### Async Operations
65
62
 
66
63
  ```typescript
67
- async function fetchUser(id: number): AsyncResult<User, Error> {
64
+ async function fetchUser(id: number): ResultAsync<User, Error> {
68
65
  try {
69
66
  const response = await fetch(`/api/users/${id}`);
70
67
  if (!response.ok) {
71
- return err(new Error(`HTTP ${response.status}`));
68
+ return ResultAsync.err(new Error(`HTTP ${response.status}`));
72
69
  }
73
70
  const user = await response.json();
74
- return ok(user);
71
+
72
+ return ResultAsync.ok(user);
75
73
  } catch (error) {
76
- return err(error instanceof Error ? error : new Error("Unknown error"));
74
+ return ResultAsync.err(error instanceof Error ? error : new Error("Unknown error"));
77
75
  }
78
76
  }
79
77
  ```
80
78
 
81
- `AsyncResult<T, E>` is just `Promise<Result<T, E>>`. It's a type alias, not a class, not a wrapper, not a monad.
79
+ `ResultAsync<T, E>` is just `Promise<ResultSync<T, E>>`. It's a type alias.
82
80
 
83
81
  ### Custom Error Types
84
82
 
@@ -93,17 +91,18 @@ class ValidationError extends Error {
93
91
  }
94
92
  }
95
93
 
96
- function validateEmail(email: string): Result<string, ValidationError> {
94
+ function validateEmail(email: string): ResultSync<string, ValidationError> {
97
95
  if (!email.includes("@")) {
98
- return err(new ValidationError(400, "bad-email"));
96
+ return ResultSync.err(new ValidationError(400, "bad-email"));
99
97
  }
100
- return ok(email);
98
+
99
+ return ResultSync.ok(email);
101
100
  }
102
101
 
103
102
  const result = validateEmail("invalid-email");
104
103
  if (result.isError) {
105
104
  // TypeScript knows this is a ValidationError, not just Error
106
- console.log(`${result.error.code}: ${result.error.message}`); // 400: bad-email
105
+ console.log(`${result.error.code}:${result.error.message}`); // 400: bad-email
107
106
  }
108
107
  ```
109
108
 
package/build/index.d.ts CHANGED
@@ -1,16 +1,23 @@
1
1
  //#region src/index.d.ts
2
- type Result<T, E extends Error> = {
2
+ type SyncResult<T, E extends Error> = {
3
3
  readonly isError: false;
4
- readonly isOk: true;
5
4
  readonly value: T;
6
5
  } | {
7
6
  readonly isError: true;
8
- readonly isOk: false;
9
7
  readonly error: E;
10
8
  };
11
- type AsyncResult<T, E extends Error> = Promise<Result<T, E>>;
12
- declare function ok<T>(value: T): Result<T, never>;
13
- declare function err<E extends Error>(error: E): Result<never, E>;
9
+ declare const ok: <T>(value: T) => SyncResult<T, never>;
10
+ declare const err: <E extends Error>(error: E) => SyncResult<never, E>;
11
+ type ResultSync<T, E extends Error> = SyncResult<T, E>;
12
+ declare const ResultSync: {
13
+ ok: typeof ok;
14
+ err: typeof err;
15
+ };
16
+ type ResultAsync<T, E extends Error> = Promise<SyncResult<T, E>>;
17
+ declare const ResultAsync: {
18
+ ok: typeof ok;
19
+ err: typeof err;
20
+ };
14
21
  //#endregion
15
- export { AsyncResult, Result, err, ok };
22
+ export { ResultAsync, ResultSync };
16
23
  //# sourceMappingURL=index.d.ts.map
package/build/index.js CHANGED
@@ -4,26 +4,48 @@
4
4
  * @param value The success value
5
5
  * @returns A Result object representing success
6
6
  */
7
- function ok(value) {
8
- return {
9
- isError: false,
10
- isOk: true,
11
- value
12
- };
13
- }
7
+ const ok = (value) => ({
8
+ isError: false,
9
+ value
10
+ });
14
11
  /**
15
12
  * Creates an error Result with the given error.
16
13
  * @param error The error value
17
14
  * @returns A Result object representing error
18
15
  */
19
- function err(error) {
20
- return {
21
- isError: true,
22
- isOk: false,
23
- error
24
- };
25
- }
26
-
16
+ const err = (error) => ({
17
+ isError: true,
18
+ error
19
+ });
20
+ const ResultSync = {
21
+ /**
22
+ * Creates a successful Result with the given value.
23
+ * @param value The success value
24
+ * @returns A Result object representing success
25
+ */
26
+ ok,
27
+ /**
28
+ * Creates an error Result with the given error.
29
+ * @param error The error value
30
+ * @returns A Result object representing error
31
+ */
32
+ err
33
+ };
34
+ const ResultAsync = {
35
+ /**
36
+ * Creates a successful Result with the given value.
37
+ * @param value The success value
38
+ * @returns A Result object representing success
39
+ */
40
+ ok,
41
+ /**
42
+ * Creates an error Result with the given error.
43
+ * @param error The error value
44
+ * @returns A Result object representing error
45
+ */
46
+ err
47
+ };
27
48
  //#endregion
28
- export { err, ok };
49
+ export { ResultAsync, ResultSync };
50
+
29
51
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * Result type to represent the outcome of an operation.\n * It can either be a success with a value or an error.\n * This is a generic type that can be used with any type of value and error (should extend Error).\n *\n * It is also an alias object containing the ok and error functions to\n * make it easier to create Result objects.\n */\nexport type Result<T, E extends Error> =\n | { readonly isError: false; readonly isOk: true; readonly value: T }\n | { readonly isError: true; readonly isOk: false; readonly error: E };\n\n/**\n * Async version of Result type that wraps a Result in a Promise.\n */\nexport type AsyncResult<T, E extends Error> = Promise<Result<T, E>>;\n\n/**\n * Creates a successful Result with the given value.\n * @param value The success value\n * @returns A Result object representing success\n */\nexport function ok<T>(value: T): Result<T, never> {\n return { isError: false, isOk: true, value };\n}\n\n/**\n * Creates an error Result with the given error.\n * @param error The error value\n * @returns A Result object representing error\n */\nexport function err<E extends Error>(error: E): Result<never, E> {\n return { isError: true, isOk: false, error };\n}\n"],"mappings":";;;;;;AAsBA,SAAgB,GAAM,OAA4B;AAChD,QAAO;EAAE,SAAS;EAAO,MAAM;EAAM;EAAO;;;;;;;AAQ9C,SAAgB,IAAqB,OAA4B;AAC/D,QAAO;EAAE,SAAS;EAAM,MAAM;EAAO;EAAO"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["type SyncResult<T, E extends Error> =\n | { readonly isError: false; readonly value: T }\n | { readonly isError: true; readonly error: E };\n\n/**\n * Creates a successful Result with the given value.\n * @param value The success value\n * @returns A Result object representing success\n */\nconst ok = <T>(value: T): SyncResult<T, never> => ({\n isError: false,\n value,\n});\n\n/**\n * Creates an error Result with the given error.\n * @param error The error value\n * @returns A Result object representing error\n */\nconst err = <E extends Error>(error: E): SyncResult<never, E> => ({\n isError: true,\n error,\n});\n\n/**\n * Result type to represent the synchronous outcome of an operation.\n * It can either be a success with a value or an error.\n *\n * It is also an object containing the ok and err functions to\n * make it easier to create Result objects.\n */\nexport type ResultSync<T, E extends Error> = SyncResult<T, E>;\n\nexport const ResultSync = {\n /**\n * Creates a successful Result with the given value.\n * @param value The success value\n * @returns A Result object representing success\n */\n ok,\n /**\n * Creates an error Result with the given error.\n * @param error The error value\n * @returns A Result object representing error\n */\n err,\n};\n\n/**\n * Async version of Result type that wraps a Result in a Promise.\n *\n * It is also an object containing the ok and err functions to\n * make it easier to create Result objects for async workflows.\n */\nexport type ResultAsync<T, E extends Error> = Promise<SyncResult<T, E>>;\n\nexport const ResultAsync = {\n /**\n * Creates a successful Result with the given value.\n * @param value The success value\n * @returns A Result object representing success\n */\n ok,\n /**\n * Creates an error Result with the given error.\n * @param error The error value\n * @returns A Result object representing error\n */\n err,\n};\n"],"mappings":";;;;;;AASA,MAAM,MAAS,WAAoC;CACjD,SAAS;CACT;AACF;;;;;;AAOA,MAAM,OAAwB,WAAoC;CAChE,SAAS;CACT;AACF;AAWA,MAAa,aAAa;;;;;;CAMxB;;;;;;CAMA;AACF;AAUA,MAAa,cAAc;;;;;;CAMzB;;;;;;CAMA;AACF"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mkvlrn/result",
3
3
  "description": "Simple Result type/pattern for TypeScript",
4
- "version": "5.0.8",
4
+ "version": "6.0.1",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "author": "Mike Valeriano <mkvlrn@gmail.com>",
@@ -9,6 +9,10 @@
9
9
  "type": "git",
10
10
  "url": "git@github.com:mkvlrn/tools"
11
11
  },
12
+ "publishConfig": {
13
+ "access": "public",
14
+ "registry": "https://registry.npmjs.org/"
15
+ },
12
16
  "keywords": [
13
17
  "node",
14
18
  "typescript",
@@ -25,15 +29,13 @@
25
29
  "default": "./build/index.js"
26
30
  },
27
31
  "devDependencies": {
28
- "@types/node": "^25.3.3",
29
- "lint-staged": "^16.3.2",
32
+ "@types/node": "^26.1.1",
30
33
  "tsc-files": "^1.1.4",
31
- "tsdown": "0.20.3",
32
- "typescript": "6.0.0-beta",
33
- "vitest": "^4.0.18"
34
+ "tsdown": "0.22.14",
35
+ "typescript": "^7.0.2",
36
+ "vitest": "^4.1.10"
34
37
  },
35
38
  "scripts": {
36
- "build": "tsdown",
37
- "typecheck": "tsc --noEmit"
39
+ "build": "tsdown"
38
40
  }
39
41
  }