@shkumbinhsn/try-catch 0.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 ADDED
@@ -0,0 +1,100 @@
1
+ # Type-Safe Try-Catch Pattern for TypeScript
2
+
3
+ This repository demonstrates an experimental approach to handling try-catch blocks in TypeScript with enhanced type safety and flexibility. This pattern allows developers to explicitly define the types of errors that can be thrown while maintaining compatibility with traditional try-catch usage.
4
+
5
+ ## Key Features
6
+
7
+ 1. **Full TypeScript Flexibility**:
8
+ - Use the `Throws` utility to define the types of errors a function might throw.
9
+ - If type definitions are not needed, the function works like a traditional try-catch and returns a tuple `[data, error]`.
10
+
11
+ 2. **Explicit Error Types**:
12
+ - For functions throwing multiple errors (e.g., `CustomError`, `Error`), use `Throws` to explicitly declare them.
13
+
14
+ 3. **Ease of Use**:
15
+ - Handle returned tuples with an `if` statement to separate success from failure cases.
16
+
17
+ ## Limitations
18
+
19
+ - **Duplicate Definitions**:
20
+ - Errors need to be defined twice: once for throwing them and once in the return type. This is a design choice to ensure type safety, but it does not affect runtime behavior.
21
+
22
+ ---
23
+
24
+ ## Example Code
25
+
26
+ ### Defining a Function with Error Handling
27
+
28
+ ```typescript
29
+ import { tryCatch, type Throws } from "./lib/try-catch";
30
+
31
+ class CustomError extends Error {}
32
+
33
+ function iMightFail(): string & Throws<CustomError> {
34
+ const random = Math.random();
35
+ if (random > 0.2) {
36
+ return "success";
37
+ } else if (random > 0.5) {
38
+ throw new CustomError();
39
+ }
40
+ throw new Error();
41
+ }
42
+
43
+ const [data, error] = tryCatch(() => iMightFail());
44
+
45
+ if (error1) {
46
+ console.log("i Might fail failed", error.message);
47
+ // ^? Error | CustomError
48
+ } else {
49
+ console.log("i succeeded", data);
50
+ // ^? string
51
+ }
52
+
53
+ ```
54
+
55
+ ### Async Functions with Errors
56
+
57
+ ```typescript
58
+ function sleep(ms: number) {
59
+ return new Promise(resolve => setTimeout(resolve, ms));
60
+ }
61
+
62
+ async function iMightFailAsync(): Promise<string & Throws<CustomError>> {
63
+ await sleep(200);
64
+ const random = Math.random();
65
+ if (random > 0.2) {
66
+ return "success";
67
+ } else if (random > 0.5) {
68
+ throw new CustomError();
69
+ }
70
+ throw new Error();
71
+ }
72
+
73
+ const [data, error] = await tryCatch(() => iMightFailAsync());
74
+
75
+ if (error2) {
76
+ console.log("i Might fail async failed", error.message);
77
+ // ^? Error | CustomError
78
+ } else {
79
+ console.log("i Might fail async succeeded", data);
80
+ // ^? string
81
+ }
82
+ ```
83
+
84
+ ### With normal typescript inference
85
+
86
+ ```typescript
87
+ function iMightFailOrNot() {
88
+ return "success"
89
+ }
90
+
91
+ const [data3, error3] = tryCatch(iMightFailOrNot);
92
+
93
+ if (error3) {
94
+ console.log("i Might fail or not failed", error3.message)
95
+ // ^? Error
96
+ } else {
97
+ console.log("i Might fail or not succeeded", data3)
98
+ // ^? string
99
+ }
100
+ ```
@@ -0,0 +1,26 @@
1
+ const errorSymbol = Symbol();
2
+ type ErrorSymbol = typeof errorSymbol;
3
+
4
+ export type Throws<T extends Error> = {
5
+ [errorSymbol]?: T
6
+ };
7
+
8
+ type ExtractErrors<T> = T extends Throws<infer E> ? E : never;
9
+
10
+ type Simplify<T> = T extends any ? { [K in keyof T]: T[K] } : never;
11
+
12
+ type ExtractData<T> =
13
+ T extends string ? string :
14
+ T extends number ? number :
15
+ T extends boolean ? boolean :
16
+ T extends symbol ? symbol :
17
+ T extends bigint ? bigint :
18
+ T extends null ? null :
19
+ T extends undefined ? undefined :
20
+ T extends Function ? T :
21
+ Simplify<Omit<T, ErrorSymbol>>;
22
+
23
+ type DataError<T> = [ExtractData<T>, null] | [null, Error | ExtractErrors<T>];
24
+ type TryCatchReturn<T> = T extends Promise<infer R> ? Promise<DataError<R>> : DataError<T>;
25
+
26
+ export declare function tryCatch<T>(fn: () => T): TryCatchReturn<T>;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Executes a function within a try-catch block and returns a tuple [data, error].
3
+ *
4
+ * @param {Function} fn - The function to execute. Can be synchronous or return a Promise.
5
+ * @returns {Array|Promise<Array>} A tuple where:
6
+ * - For success: [data, null] where data is the function's return value
7
+ * - For failure: [null, error] where error is the caught exception
8
+ *
9
+ * @example
10
+ * // Synchronous usage
11
+ * const [data, error] = tryCatch(() => riskyFunction());
12
+ *
13
+ * @example
14
+ * // Asynchronous usage
15
+ * const [data, error] = await tryCatch(() => asyncRiskyFunction());
16
+ */
17
+ export function tryCatch(fn) {
18
+ try {
19
+ const result = fn();
20
+ if(result instanceof Promise) {
21
+ return new Promise((resolve) => {
22
+ result.then((data) => resolve([data, null])).catch((error) => resolve([null, error]))
23
+ })
24
+ }
25
+ return [result, null];
26
+ } catch (e) {
27
+ return [null, e]
28
+ }
29
+ }
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@shkumbinhsn/try-catch",
3
+ "version": "0.0.1",
4
+ "description": "A utility package for handling try-catch blocks in TypeScript.",
5
+ "main": "./lib/try-catch.js",
6
+ "module": "./lib/try-catch.js",
7
+ "types": "./lib/try-catch.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./lib/try-catch.d.ts",
11
+ "import": "./lib/try-catch.js",
12
+ "require": "./lib/try-catch.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "lib"
17
+ ],
18
+ "engines": {
19
+ "node": ">=16"
20
+ },
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
24
+ "scripts": {
25
+ "test": "echo \"No test specified\" && exit 0"
26
+ },
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "https://github.com/shkumbinhasani/ts-try-catch"
30
+ },
31
+ "keywords": [
32
+ "typescript",
33
+ "try-catch",
34
+ "error-handling",
35
+ "type-safe",
36
+ "utility",
37
+ "exception-handling",
38
+ "functional-programming",
39
+ "result-type"
40
+ ],
41
+ "author": "Shkumbin Hasani",
42
+ "license": "MIT",
43
+ "devDependencies": {
44
+ "typescript": "^5.0.0"
45
+ }
46
+ }