@shkumbinhsn/try-catch 0.0.1 → 0.0.3

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
@@ -1,23 +1,33 @@
1
+ ![cowboy trying to catch a horse](https://i.imgur.com/TzMOUUL.jpeg)
2
+ [![npm version](https://img.shields.io/npm/v/@shkumbinhsn/try-catch.svg)](https://www.npmjs.com/package/@shkumbinhsn/try-catch)
3
+ [![npm downloads](https://img.shields.io/npm/dm/@shkumbinhsn/try-catch.svg)](https://www.npmjs.com/package/@shkumbinhsn/try-catch)
1
4
  # Type-Safe Try-Catch Pattern for TypeScript
2
5
 
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.
6
+ A lightweight TypeScript utility that provides type-safe error handling through a functional approach. This library allows you to explicitly define error types while maintaining full TypeScript inference and zero runtime overhead.
4
7
 
5
- ## Key Features
8
+ ## Installation
6
9
 
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
+ ```bash
11
+ npm install @shkumbinhsn/try-catch
12
+ ```
10
13
 
11
- 2. **Explicit Error Types**:
12
- - For functions throwing multiple errors (e.g., `CustomError`, `Error`), use `Throws` to explicitly declare them.
14
+ ## Key Features
13
15
 
14
- 3. **Ease of Use**:
15
- - Handle returned tuples with an `if` statement to separate success from failure cases.
16
+ - **🔒 Type Safety**: Explicitly declare what errors your functions can throw
17
+ - **🎯 Zero Runtime Overhead**: Types are compile-time only using TypeScript's structural typing
18
+ - **🔄 Async/Sync Support**: Works seamlessly with both synchronous and asynchronous functions
19
+ - **📦 Lightweight**: Minimal footprint with no dependencies
20
+ - **🧠 Smart Inference**: Falls back to standard TypeScript inference when no error types are specified
21
+ - **🛡️ Tuple-based**: Returns `[data, error]` tuples for explicit error handling
16
22
 
17
- ## Limitations
23
+ ## Why Use This Pattern?
24
+
25
+ Traditional try-catch blocks in TypeScript don't provide type information about what errors might be thrown. This library solves that by:
18
26
 
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.
27
+ 1. Making error types explicit in function signatures
28
+ 2. Forcing explicit error handling through tuple destructuring
29
+ 3. Providing better IntelliSense and type checking
30
+ 4. Maintaining compatibility with existing code
21
31
 
22
32
  ---
23
33
 
@@ -26,7 +36,7 @@ This repository demonstrates an experimental approach to handling try-catch bloc
26
36
  ### Defining a Function with Error Handling
27
37
 
28
38
  ```typescript
29
- import { tryCatch, type Throws } from "./lib/try-catch";
39
+ import { tryCatch, type Throws } from "@shkumbinhsn/try-catch";
30
40
 
31
41
  class CustomError extends Error {}
32
42
 
@@ -35,66 +45,108 @@ function iMightFail(): string & Throws<CustomError> {
35
45
  if (random > 0.2) {
36
46
  return "success";
37
47
  } else if (random > 0.5) {
38
- throw new CustomError();
48
+ throw new CustomError("Something went wrong");
39
49
  }
40
- throw new Error();
50
+ throw new Error("Generic error");
41
51
  }
42
52
 
43
53
  const [data, error] = tryCatch(() => iMightFail());
44
54
 
45
- if (error1) {
46
- console.log("i Might fail failed", error.message);
47
- // ^? Error | CustomError
55
+ if (error) {
56
+ console.log("Operation failed:", error.message);
57
+ // TypeScript knows: error is Error | CustomError
48
58
  } else {
49
- console.log("i succeeded", data);
50
- // ^? string
59
+ console.log("Operation succeeded:", data);
60
+ // TypeScript knows: data is string
51
61
  }
52
-
53
62
  ```
54
63
 
55
64
  ### Async Functions with Errors
56
65
 
57
66
  ```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();
67
+ async function fetchUserData(id: string): Promise<User & Throws<ValidationError | NetworkError>> {
68
+ if (!id) {
69
+ throw new ValidationError("User ID is required");
70
+ }
71
+
72
+ const response = await fetch(`/api/users/${id}`);
73
+ if (!response.ok) {
74
+ throw new NetworkError("Failed to fetch user data");
69
75
  }
70
- throw new Error();
76
+
77
+ return response.json();
71
78
  }
72
79
 
73
- const [data, error] = await tryCatch(() => iMightFailAsync());
80
+ const [userData, error] = await tryCatch(() => fetchUserData("123"));
74
81
 
75
- if (error2) {
76
- console.log("i Might fail async failed", error.message);
77
- // ^? Error | CustomError
82
+ if (error) {
83
+ if (error instanceof ValidationError) {
84
+ console.log("Validation error:", error.message);
85
+ } else if (error instanceof NetworkError) {
86
+ console.log("Network error:", error.message);
87
+ } else {
88
+ console.log("Unexpected error:", error.message);
89
+ }
78
90
  } else {
79
- console.log("i Might fail async succeeded", data);
80
- // ^? string
91
+ console.log("User data:", userData);
92
+ // TypeScript knows: userData is User
81
93
  }
82
94
  ```
83
95
 
84
- ### With normal typescript inference
96
+ ### Without Explicit Error Types
97
+
98
+ When you don't specify error types, the library falls back to standard TypeScript inference:
85
99
 
86
100
  ```typescript
87
- function iMightFailOrNot() {
88
- return "success"
101
+ function regularFunction() {
102
+ return "success";
89
103
  }
90
104
 
91
- const [data3, error3] = tryCatch(iMightFailOrNot);
105
+ const [data, error] = tryCatch(regularFunction);
92
106
 
93
- if (error3) {
94
- console.log("i Might fail or not failed", error3.message)
95
- // ^? Error
107
+ if (error) {
108
+ console.log("Operation failed:", error.message);
109
+ // TypeScript knows: error is Error
96
110
  } else {
97
- console.log("i Might fail or not succeeded", data3)
98
- // ^? string
111
+ console.log("Operation succeeded:", data);
112
+ // TypeScript knows: data is string
99
113
  }
100
114
  ```
115
+
116
+ ## API Reference
117
+
118
+ ### `tryCatch<T>(fn: () => T): TryCatchReturn<T>`
119
+
120
+ Executes a function within a try-catch block and returns a result tuple.
121
+
122
+ **Parameters:**
123
+ - `fn`: Function to execute (can be sync or async)
124
+
125
+ **Returns:**
126
+ - `[data, null]` on success
127
+ - `[null, error]` on failure
128
+
129
+ ### `Throws<T extends Error>`
130
+
131
+ Type utility for declaring error types in function signatures.
132
+
133
+ **Usage:**
134
+ ```typescript
135
+ function myFunction(): ReturnType & Throws<MyError> {
136
+ // function implementation
137
+ }
138
+ ```
139
+
140
+ ## Limitations
141
+
142
+ - **Duplicate Definitions**: Error types must be declared in both the throw statement and return type
143
+ - **Runtime Validation**: No runtime enforcement of declared error types
144
+ - **Learning Curve**: Requires understanding of TypeScript's structural typing
145
+
146
+ ## Contributing
147
+
148
+ Contributions are welcome! Please feel free to submit issues and pull requests.
149
+
150
+ ## License
151
+
152
+ MIT
@@ -1,4 +1,5 @@
1
1
  const errorSymbol = Symbol();
2
+
2
3
  type ErrorSymbol = typeof errorSymbol;
3
4
 
4
5
  export type Throws<T extends Error> = {
@@ -7,20 +8,12 @@ export type Throws<T extends Error> = {
7
8
 
8
9
  type ExtractErrors<T> = T extends Throws<infer E> ? E : never;
9
10
 
10
- type Simplify<T> = T extends any ? { [K in keyof T]: T[K] } : never;
11
+ type StripThrows<T> = T extends infer R & Throws<Error> ? R : T;
11
12
 
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>>;
13
+ type DataError<T> = [StripThrows<T>, null] | [null, Error | ExtractErrors<T>];
22
14
 
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>;
15
+ type TryCatchReturn<T> = T extends Promise<infer R>
16
+ ? Promise<DataError<R>>
17
+ : DataError<T>;
25
18
 
26
- export declare function tryCatch<T>(fn: () => T): TryCatchReturn<T>;
19
+ export declare function tryCatch<T>(fn: () => T): TryCatchReturn<T>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shkumbinhsn/try-catch",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "A utility package for handling try-catch blocks in TypeScript.",
5
5
  "main": "./lib/try-catch.js",
6
6
  "module": "./lib/try-catch.js",
@@ -22,11 +22,11 @@
22
22
  "access": "public"
23
23
  },
24
24
  "scripts": {
25
- "test": "echo \"No test specified\" && exit 0"
25
+ "test": "tsc -p tsconfig.json"
26
26
  },
27
27
  "repository": {
28
28
  "type": "git",
29
- "url": "https://github.com/shkumbinhasani/ts-try-catch"
29
+ "url": "git+https://github.com/shkumbinhasani/ts-try-catch.git"
30
30
  },
31
31
  "keywords": [
32
32
  "typescript",