@@ -10,6 +10,8 @@ See [Theo's gist for more details](https://gist.github.com/t3dotgg/a486c4ae66d32
1010- Returns a structured tuple ` [data, error] ` .
1111- Provides named operations for better debugging.
1212- Includes ` tryCatch.sync ` and ` tryCatch.async ` for explicit handling.
13+ - Allows custom error types via ` .errors<E>() `
14+ - Ensures all thrown values become ` Error ` instances
1315
1416## Installation
1517
@@ -24,60 +26,150 @@ npm install @maxmorozoff/try-catch-tuple
2426``` ts
2527import { tryCatch } from " @maxmorozoff/try-catch-tuple" ;
2628
27- const [result, error] = tryCatch .sync (() => JSON .parse (" 73" ));
28- console .log (result ); // 73
29- console .log (error ); // null
29+ function main() {
30+ const [result, error] = tryCatch (() => JSON .parse (" 73" ) as number );
31+ // ^? const result: number | null
32+
33+ if (! error ) return result ; // ✅ result: number
34+ console .log (error ); // ❌ Error
35+ // ^? const error: Error
36+ }
3037```
3138
32- ### Handling Errors
39+ ### Named Operations for Debugging
3340
3441``` ts
3542const [result, error] = tryCatch ((): void => {
36- throw new Error (" Something went wrong" );
37- });
43+ throw new Error (" Failed to fetch data" );
44+ }, " Fetch Data" );
45+
46+ console .log (error ?.message ); // "Operation \"Fetch Data\" failed: Failed to fetch data"
47+ ```
48+
49+ ### Using ` tryCatch.sync `
3850
39- console .log (result ); // null
40- console .log (error ?.message ); // "Something went wrong"
51+ ``` ts
52+ function main() {
53+ const [result, error] = tryCatch .sync (() => JSON .parse (" 73" ) as number );
54+ // ^? const result: number | null
55+ if (! error ) return result ;
56+ // ^? const result: number
57+ error ;
58+ // ^? const error: Error
59+ result ;
60+ // ^? const result: null
61+ }
4162```
4263
43- ### Asynchronous Usage with Errors
64+ ### Using ` tryCatch.async `
4465
4566``` ts
46- const [result, error] = await tryCatch (async () => {
47- throw new Error (" Network request failed" );
67+ async function main() {
68+ const [result, error] = await tryCatch .async (
69+ // ^? const result: number | null
70+ async () => JSON .parse (" 73" ) as number
71+ );
72+ if (! error ) return result ;
73+ // ^? const result: number
74+ error ;
75+ // ^? const error: Error
76+ result ;
77+ // ^? const result: null
78+ }
79+ ```
80+
81+ ### Handling Errors
82+
83+ #### Ensuring All Thrown Values Are Error Instances
84+
85+ If a thrown value is ** not an instance of** ` Error ` , it gets wrapped:
86+
87+ ``` ts
88+ const [result, error] = tryCatch ((): void => {
89+ throw " Something went wrong" ;
4890});
4991
50- console .log (result ); // null
51- console .log (error ?.message ); // "Network request failed"
92+ console .log (error .message ); // "Something went wrong"
93+ // ^? const error: Error
94+
95+ const [data, nullError] = tryCatch ((): void => {
96+ throw null ;
97+ });
98+
99+ console .log (nullError .message ); // "null"
100+ // ^? const error: Error
101+ console .log (nullError .cause ); // null
52102```
53103
54- ### Named Operations for Debugging
104+ This ensures tryCatch always provides a proper error object.
105+
106+ #### Extending Error types
107+
108+ ##### Option 1: Manually Set Result and Error Type
55109
56110``` ts
57- const [result, error] = tryCatch (() => {
58- throw new Error (" Failed to fetch data" );
59- }, " Fetch Data" );
111+ type User = { id: number ; name: string };
60112
61- console .log (error ?.message ); // "Operation \"Fetch Data\" failed: Failed to fetch data"
113+ async function main() {
114+ const [user, error] = await tryCatch <Promise <User >, SyntaxError >(
115+ fetchUser (1 )
116+ );
117+
118+ if (! error ) return user ; // ✅ user: User
119+ console .error (error ); // ❌ SyntaxError | Error
120+ }
62121```
63122
64- ### Using ` tryCatch.sync `
123+ ##### Option 2: Using ` tryCatch.errors<E>() ` Helper
65124
66125``` ts
67- const [result, error] = tryCatch .sync (() => JSON .parse (" INVALID_JSON" ));
68- console .log (result ); // null
69- console .log (error ?.message ); // "Unexpected token I in JSON"
126+ async function main() {
127+ const [user, error] = await tryCatch .errors <SyntaxError >()(fetchUser (1 ));
128+
129+ if (! error ) return user ; // ✅ user: User
130+ console .error (error ); // ❌ Error | SyntaxError
131+ }
70132```
71133
72- ### Using ` tryCatch.async `
134+ ### Wrapping Functions for Reuse
135+
136+ To avoid repetitive tryCatch calls, you can wrap functions:
73137
74138``` ts
75- const [result, error] = await tryCatch .async (async () => {
76- throw new Error (" Async operation failed" );
77- });
139+ const getUser = (id : number ) =>
140+ tryCatch
141+ .errors <RangeError >()
142+ .errors <SyntaxError | TypeError | DOMException >()
143+ .async (fetchUser (id ));
144+
145+ // Or simply:
146+ // const getUser = (id: number) => tryCatch(fetchUser(id));
147+
148+ async function main() {
149+ const [user, error] = await getUser (1 );
150+
151+ if (! error ) return user ; // ✅ user: User
152+ console .error (error ); // ❌ Error | RangeError | SyntaxError | TypeError | DOMException
153+ }
154+ ```
78155
79- console .log (result ); // null
80- console .log (error ?.message ); // "Async operation failed"
156+ ### Using in React Server Components (RSC)
157+
158+ ``` tsx
159+ const getUser = (id : number ) =>
160+ tryCatch .errors <SyntaxError | TypeError | DOMException >()(fetchUser (id ));
161+
162+ async function UserPage({ id }: { id: number }) {
163+ const [user, error] = await getUser (id );
164+
165+ if (! error ) return <div >Hello { user .name } !</div >;
166+
167+ if (error instanceof SyntaxError ) {
168+ return <div >Error: { error .message } </div >;
169+ }
170+
171+ return <div >Not found</div >;
172+ }
81173```
82174
83175### Comparing ` tryCatch ` with ` try...catch `
@@ -89,11 +181,11 @@ async function goodFunc() {
89181}
90182
91183async function badFunc() {
92- throw " no data" ;
93- return " " ;
184+ if ( true ) throw " no data" ;
185+ return " some data " ;
94186}
95187
96- // Using tryCatch
188+ // ✅ Using tryCatch
97189const getData = async () => {
98190 let [data, err] = await tryCatch (badFunc );
99191 if (! err ) return Response .json ({ data });
@@ -107,7 +199,7 @@ const getData = async () => {
107199 return Response .error ();
108200};
109201
110- // Using tryCatch with constants
202+ // ✅ Using tryCatch with constants
111203const getDataConst = async () => {
112204 const [data1, err1] = await tryCatch (badFunc );
113205 if (! err1 ) return Response .json ({ data: data1 });
@@ -121,7 +213,7 @@ const getDataConst = async () => {
121213 return Response .error ();
122214};
123215
124- // Using try...catch
216+ // ❌ Using traditional try...catch (deep nesting)
125217const getDataStandard = async () => {
126218 try {
127219 const data = await badFunc ();
@@ -144,22 +236,31 @@ const getDataStandard = async () => {
144236
145237## API Reference
146238
147- ### ` tryCatch<T>(fn: (() => T) | T, operationName?: string): Result<T> `
239+ ### Main Function
148240
149- Handles both values and functions that may throw errors.
241+ ``` ts
242+ tryCatch <T , E extends Error = never >(fn ? : (() => T ) | T | Promise <T > | (() => Promise <T >), operationName ? : string ): Result <T , E >
243+ ` ` `
150244
151- ### ` tryCatch.sync<T>(fn: () => T, operationName?: string): Result<T> `
245+ - Handles values, sync/async functions
246+ - Automatically detects Promises
152247
153- Explicitly handles synchronous operations.
248+ ### Explicit Synchronous Handling
154249
155- ### ` tryCatch.async<T>(fn: Promise<T> | (() => Promise<T>), operationName?: string): Promise<Result<T>> `
250+ ` ` ` ts
251+ tryCatch .sync <T , E extends Error = never >(fn : () => T , operationName ? : string ): Result <T , E >
252+ ` ` `
156253
157- Explicitly handles asynchronous operations.
254+ ### Explicit Asynchronous Handling
255+
256+ ` ` ` ts
257+ tryCatch .async <T , E extends Error = never >(fn : Promise <T > | (() => Promise <T >), operationName ? : string ): Promise <Result <T , E >>
258+ ` ` `
158259
159260## Result Type
160261
161262` ` ` ts
162- type Result <T , E = Error > = [data : T | null , error : E | null ];
263+ type Result <T , E = Error > = [data : T , error : null ] | [ data : null , error : E ];
163264` ` `
164265
165266## Edge Cases
@@ -169,7 +270,7 @@ tryCatch(); // Returns [undefined, null]
169270tryCatch (null ); // Returns [null, null]
170271tryCatch (() => {
171272 throw new Error(" Unexpected Error" );
172- }); // Handles thrown errors
273+ }); // Returns [null, Error]
173274tryCatch (Promise .reject (new Error (" Promise rejected" ))); // Handles rejected promises
174275` ` `
175276
0 commit comments