@firtoz/maybe-error 1.5.1 → 1.6.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 +6 -1
- package/dist/MaybeError.d.ts +135 -0
- package/dist/MaybeError.js +3 -0
- package/dist/MaybeError.js.map +1 -0
- package/dist/chunk-FAVWW3FP.js +20 -0
- package/dist/chunk-FAVWW3FP.js.map +1 -0
- package/dist/chunk-Z5JSMWNM.js +8 -0
- package/dist/chunk-Z5JSMWNM.js.map +1 -0
- package/dist/exhaustiveGuard.d.ts +3 -0
- package/dist/exhaustiveGuard.js +3 -0
- package/dist/exhaustiveGuard.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/package.json +14 -9
- package/src/MaybeError.ts +2 -6
- package/src/exhaustiveGuard.ts +3 -0
- package/src/index.ts +9 -1
package/README.md
CHANGED
|
@@ -4,7 +4,12 @@
|
|
|
4
4
|
[](https://www.npmjs.com/package/@firtoz/maybe-error)
|
|
5
5
|
[](https://github.com/firtoz/fullstack-toolkit/blob/main/LICENSE)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
[](https://www.typescriptlang.org/)
|
|
8
|
+
[](https://github.com/firtoz/fullstack-toolkit/tree/main/packages/maybe-error)
|
|
9
|
+
|
|
10
|
+
**`MaybeError` results without exceptions** — discriminated unions, tree-shakeable, zero runtime dependencies.
|
|
11
|
+
|
|
12
|
+
> **⚠️ Early WIP Notice:** This package is in very early development and is **not production-ready**. It is TypeScript-only and may have breaking changes. While I (the maintainer) have limited time, I'm open to PRs for features, bug fixes, or additional support (like JS builds). Please feel free to try it out and contribute! See [CONTRIBUTING.md](../../CONTRIBUTING.md) for details.
|
|
8
13
|
|
|
9
14
|
## Features
|
|
10
15
|
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Type-safe error handling utilities using discriminated unions
|
|
3
|
+
*
|
|
4
|
+
* This module provides a Result-like pattern for handling operations that may fail,
|
|
5
|
+
* inspired by Rust's Result type and functional programming error handling patterns.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* // Basic usage
|
|
10
|
+
* const result = success(42);
|
|
11
|
+
* const error = fail("Something went wrong");
|
|
12
|
+
*
|
|
13
|
+
* // Type-safe error handling
|
|
14
|
+
* function divide(a: number, b: number): MaybeError<number> {
|
|
15
|
+
* if (b === 0) return fail("Division by zero");
|
|
16
|
+
* return success(a / b);
|
|
17
|
+
* }
|
|
18
|
+
*
|
|
19
|
+
* const result = divide(10, 2);
|
|
20
|
+
* if (result.success) {
|
|
21
|
+
* console.log(result.result); // 5
|
|
22
|
+
* } else {
|
|
23
|
+
* console.error(result.error); // "Division by zero"
|
|
24
|
+
* }
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
/**
|
|
28
|
+
* Represents a failed operation with an error value.
|
|
29
|
+
*
|
|
30
|
+
* @template TError - The type of the error value (defaults to string)
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* const error: DefiniteError<string> = { success: false, error: "Not found" };
|
|
34
|
+
* const customError: DefiniteError<{code: number, message: string}> = {
|
|
35
|
+
* success: false,
|
|
36
|
+
* error: { code: 404, message: "Resource not found" }
|
|
37
|
+
* };
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
type DefiniteError<TError = string> = {
|
|
41
|
+
success: false;
|
|
42
|
+
error: TError;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Represents a successful operation with an optional result value.
|
|
46
|
+
*
|
|
47
|
+
* Uses conditional types to make the result field optional when T is undefined,
|
|
48
|
+
* but required when T has a concrete type.
|
|
49
|
+
*
|
|
50
|
+
* @template T - The type of the success value (defaults to undefined)
|
|
51
|
+
* @example
|
|
52
|
+
* ```typescript
|
|
53
|
+
* const voidSuccess: DefiniteSuccess = { success: true };
|
|
54
|
+
* const valueSuccess: DefiniteSuccess<number> = { success: true, result: 42 };
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
type DefiniteSuccess<T = undefined> = {
|
|
58
|
+
success: true;
|
|
59
|
+
} & (T extends undefined ? {
|
|
60
|
+
result?: T;
|
|
61
|
+
} : {
|
|
62
|
+
result: T;
|
|
63
|
+
});
|
|
64
|
+
/**
|
|
65
|
+
* A discriminated union representing either a successful result or an error.
|
|
66
|
+
*
|
|
67
|
+
* This is the main type for operations that may fail. The `success` field
|
|
68
|
+
* acts as a discriminant, allowing TypeScript to narrow the type in conditionals.
|
|
69
|
+
*
|
|
70
|
+
* @template T - The type of the success value (defaults to undefined)
|
|
71
|
+
* @template TError - The type of the error value (defaults to string)
|
|
72
|
+
* @example
|
|
73
|
+
* ```typescript
|
|
74
|
+
* function fetchUser(id: string): MaybeError<User, ApiError> {
|
|
75
|
+
* // Implementation that returns either success(user) or fail(apiError)
|
|
76
|
+
* }
|
|
77
|
+
*
|
|
78
|
+
* const result = fetchUser("123");
|
|
79
|
+
* if (result.success) {
|
|
80
|
+
* // TypeScript knows result.result is User
|
|
81
|
+
* console.log(result.result.name);
|
|
82
|
+
* } else {
|
|
83
|
+
* // TypeScript knows result.error is ApiError
|
|
84
|
+
* console.error(result.error.message);
|
|
85
|
+
* }
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
type MaybeError<T = undefined, TError = string> = DefiniteSuccess<T> | DefiniteError<TError>;
|
|
89
|
+
/**
|
|
90
|
+
* Utility type to extract the success value type from a MaybeError type.
|
|
91
|
+
*
|
|
92
|
+
* Useful for type manipulation when you need to work with the success type
|
|
93
|
+
* without the error handling wrapper.
|
|
94
|
+
*
|
|
95
|
+
* @template T - A MaybeError type
|
|
96
|
+
* @example
|
|
97
|
+
* ```typescript
|
|
98
|
+
* type UserResult = MaybeError<User, string>;
|
|
99
|
+
* type UserType = AssumeSuccess<UserResult>; // User
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
type AssumeSuccess<T extends MaybeError<unknown>> = Exclude<T, undefined> extends MaybeError<infer U> ? U : never;
|
|
103
|
+
/**
|
|
104
|
+
* Creates a successful result with an optional value.
|
|
105
|
+
*
|
|
106
|
+
* Uses function overloading to provide different signatures based on whether
|
|
107
|
+
* a value is provided or not.
|
|
108
|
+
*
|
|
109
|
+
* @template T - The type of the success value
|
|
110
|
+
* @param params - The success value (optional for void operations)
|
|
111
|
+
* @returns A DefiniteSuccess instance
|
|
112
|
+
* @example
|
|
113
|
+
* ```typescript
|
|
114
|
+
* const voidResult = success(); // DefiniteSuccess<undefined>
|
|
115
|
+
* const valueResult = success(42); // DefiniteSuccess<number>
|
|
116
|
+
* const stringResult = success("hello"); // DefiniteSuccess<string>
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
declare const success: <T = undefined>(...params: T extends undefined ? [] : [T]) => DefiniteSuccess<T>;
|
|
120
|
+
/**
|
|
121
|
+
* Creates a failed result with an error value.
|
|
122
|
+
*
|
|
123
|
+
* @template TError - The type of the error value
|
|
124
|
+
* @param error - The error value
|
|
125
|
+
* @returns A DefiniteError instance
|
|
126
|
+
* @example
|
|
127
|
+
* ```typescript
|
|
128
|
+
* const stringError = fail("Something went wrong");
|
|
129
|
+
* const objectError = fail({ code: 500, message: "Internal server error" });
|
|
130
|
+
* const customError = fail(new Error("Custom error"));
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
declare const fail: <TError = string>(error: TError) => DefiniteError<TError>;
|
|
134
|
+
|
|
135
|
+
export { type AssumeSuccess, type DefiniteError, type DefiniteSuccess, type MaybeError, fail, success };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"MaybeError.js"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// src/MaybeError.ts
|
|
2
|
+
var success = (...params) => {
|
|
3
|
+
if (params.length === 0) {
|
|
4
|
+
return { success: true };
|
|
5
|
+
}
|
|
6
|
+
return {
|
|
7
|
+
success: true,
|
|
8
|
+
result: params[0]
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
var fail = (error) => {
|
|
12
|
+
return {
|
|
13
|
+
success: false,
|
|
14
|
+
error
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export { fail, success };
|
|
19
|
+
//# sourceMappingURL=chunk-FAVWW3FP.js.map
|
|
20
|
+
//# sourceMappingURL=chunk-FAVWW3FP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/MaybeError.ts"],"names":[],"mappings":";AAgIO,IAAM,OAAA,GAAU,IACnB,MAAA,KACqB;AACxB,EAAA,IAAI,MAAA,CAAO,WAAW,CAAA,EAAG;AACxB,IAAA,OAAO,EAAE,SAAS,IAAA,EAAK;AAAA,EACxB;AAEA,EAAA,OAAO;AAAA,IACN,OAAA,EAAS,IAAA;AAAA,IACT,MAAA,EAAQ,OAAO,CAAC;AAAA,GACjB;AACD;AAeO,IAAM,IAAA,GAAO,CAAkB,KAAA,KAAyC;AAC9E,EAAA,OAAO;AAAA,IACN,OAAA,EAAS,KAAA;AAAA,IACT;AAAA,GACD;AACD","file":"chunk-FAVWW3FP.js","sourcesContent":["/**\n * @fileoverview Type-safe error handling utilities using discriminated unions\n *\n * This module provides a Result-like pattern for handling operations that may fail,\n * inspired by Rust's Result type and functional programming error handling patterns.\n *\n * @example\n * ```typescript\n * // Basic usage\n * const result = success(42);\n * const error = fail(\"Something went wrong\");\n *\n * // Type-safe error handling\n * function divide(a: number, b: number): MaybeError<number> {\n * if (b === 0) return fail(\"Division by zero\");\n * return success(a / b);\n * }\n *\n * const result = divide(10, 2);\n * if (result.success) {\n * console.log(result.result); // 5\n * } else {\n * console.error(result.error); // \"Division by zero\"\n * }\n * ```\n */\n\n/**\n * Represents a failed operation with an error value.\n *\n * @template TError - The type of the error value (defaults to string)\n * @example\n * ```typescript\n * const error: DefiniteError<string> = { success: false, error: \"Not found\" };\n * const customError: DefiniteError<{code: number, message: string}> = {\n * success: false,\n * error: { code: 404, message: \"Resource not found\" }\n * };\n * ```\n */\nexport type DefiniteError<TError = string> = {\n\tsuccess: false;\n\terror: TError;\n};\n\n/**\n * Represents a successful operation with an optional result value.\n *\n * Uses conditional types to make the result field optional when T is undefined,\n * but required when T has a concrete type.\n *\n * @template T - The type of the success value (defaults to undefined)\n * @example\n * ```typescript\n * const voidSuccess: DefiniteSuccess = { success: true };\n * const valueSuccess: DefiniteSuccess<number> = { success: true, result: 42 };\n * ```\n */\nexport type DefiniteSuccess<T = undefined> = {\n\tsuccess: true;\n} & (T extends undefined\n\t? {\n\t\t\tresult?: T;\n\t\t}\n\t: {\n\t\t\tresult: T;\n\t\t});\n\n/**\n * A discriminated union representing either a successful result or an error.\n *\n * This is the main type for operations that may fail. The `success` field\n * acts as a discriminant, allowing TypeScript to narrow the type in conditionals.\n *\n * @template T - The type of the success value (defaults to undefined)\n * @template TError - The type of the error value (defaults to string)\n * @example\n * ```typescript\n * function fetchUser(id: string): MaybeError<User, ApiError> {\n * // Implementation that returns either success(user) or fail(apiError)\n * }\n *\n * const result = fetchUser(\"123\");\n * if (result.success) {\n * // TypeScript knows result.result is User\n * console.log(result.result.name);\n * } else {\n * // TypeScript knows result.error is ApiError\n * console.error(result.error.message);\n * }\n * ```\n */\nexport type MaybeError<T = undefined, TError = string> =\n\t| DefiniteSuccess<T>\n\t| DefiniteError<TError>;\n\n/**\n * Utility type to extract the success value type from a MaybeError type.\n *\n * Useful for type manipulation when you need to work with the success type\n * without the error handling wrapper.\n *\n * @template T - A MaybeError type\n * @example\n * ```typescript\n * type UserResult = MaybeError<User, string>;\n * type UserType = AssumeSuccess<UserResult>; // User\n * ```\n */\nexport type AssumeSuccess<T extends MaybeError<unknown>> =\n\tExclude<T, undefined> extends MaybeError<infer U> ? U : never;\n\n/**\n * Creates a successful result with an optional value.\n *\n * Uses function overloading to provide different signatures based on whether\n * a value is provided or not.\n *\n * @template T - The type of the success value\n * @param params - The success value (optional for void operations)\n * @returns A DefiniteSuccess instance\n * @example\n * ```typescript\n * const voidResult = success(); // DefiniteSuccess<undefined>\n * const valueResult = success(42); // DefiniteSuccess<number>\n * const stringResult = success(\"hello\"); // DefiniteSuccess<string>\n * ```\n */\nexport const success = <T = undefined>(\n\t...params: T extends undefined ? [] : [T]\n): DefiniteSuccess<T> => {\n\tif (params.length === 0) {\n\t\treturn { success: true } as unknown as DefiniteSuccess<T>;\n\t}\n\n\treturn {\n\t\tsuccess: true,\n\t\tresult: params[0],\n\t} as unknown as DefiniteSuccess<T>;\n};\n\n/**\n * Creates a failed result with an error value.\n *\n * @template TError - The type of the error value\n * @param error - The error value\n * @returns A DefiniteError instance\n * @example\n * ```typescript\n * const stringError = fail(\"Something went wrong\");\n * const objectError = fail({ code: 500, message: \"Internal server error\" });\n * const customError = fail(new Error(\"Custom error\"));\n * ```\n */\nexport const fail = <TError = string>(error: TError): DefiniteError<TError> => {\n\treturn {\n\t\tsuccess: false,\n\t\terror,\n\t};\n};\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/exhaustiveGuard.ts"],"names":[],"mappings":";AAAO,SAAS,gBAAgB,KAAA,EAAqB;AACpD,EAAA,MAAM,IAAI,KAAA,CAAM,CAAA,uCAAA,EAA0C,KAAK,CAAA,CAAE,CAAA;AAClE","file":"chunk-Z5JSMWNM.js","sourcesContent":["export function exhaustiveGuard(value: never): never {\n\tthrow new Error(`Exhaustive guard triggered with value: ${value}`);\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"exhaustiveGuard.js"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
package/package.json
CHANGED
|
@@ -1,24 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@firtoz/maybe-error",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "Type-safe result handling with MaybeError pattern",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
8
9
|
"exports": {
|
|
9
10
|
".": {
|
|
10
|
-
"types": "./
|
|
11
|
-
"import": "./
|
|
12
|
-
"require": "./src/index.ts"
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
15
|
"files": [
|
|
16
|
+
"dist/**/*.js",
|
|
17
|
+
"dist/**/*.js.map",
|
|
18
|
+
"dist/**/*.d.ts",
|
|
16
19
|
"src/**/*.ts",
|
|
17
20
|
"!src/**/*.test.ts",
|
|
18
21
|
"README.md"
|
|
19
22
|
],
|
|
20
23
|
"scripts": {
|
|
21
|
-
"
|
|
24
|
+
"build": "tsup",
|
|
25
|
+
"prepack": "bun run build",
|
|
26
|
+
"typecheck": "tsgo --noEmit -p ./tsconfig.json",
|
|
22
27
|
"lint": "biome check --write src",
|
|
23
28
|
"lint:ci": "biome ci src",
|
|
24
29
|
"format": "biome format src --write",
|
|
@@ -50,6 +55,6 @@
|
|
|
50
55
|
"access": "public"
|
|
51
56
|
},
|
|
52
57
|
"devDependencies": {
|
|
53
|
-
"bun-types": "^1.3.
|
|
58
|
+
"bun-types": "^1.3.11"
|
|
54
59
|
}
|
|
55
60
|
}
|
package/src/MaybeError.ts
CHANGED
|
@@ -107,12 +107,8 @@ export type MaybeError<T = undefined, TError = string> =
|
|
|
107
107
|
* type UserType = AssumeSuccess<UserResult>; // User
|
|
108
108
|
* ```
|
|
109
109
|
*/
|
|
110
|
-
export type AssumeSuccess<T extends MaybeError<unknown>> =
|
|
111
|
-
T,
|
|
112
|
-
undefined
|
|
113
|
-
> extends MaybeError<infer U>
|
|
114
|
-
? U
|
|
115
|
-
: never;
|
|
110
|
+
export type AssumeSuccess<T extends MaybeError<unknown>> =
|
|
111
|
+
Exclude<T, undefined> extends MaybeError<infer U> ? U : never;
|
|
116
112
|
|
|
117
113
|
/**
|
|
118
114
|
* Creates a successful result with an optional value.
|