Created
February 26, 2025 13:27
-
-
Save mthomason/88c1706759522f6bd1fdf74098bfbc56 to your computer and use it in GitHub Desktop.
A fixed version of an tryCatchWrapper for TypeScript.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Types for the result object with discriminated union | |
type Success<T> = { | |
data: T; | |
error: null; | |
}; | |
type Failure<E> = { | |
data: null; | |
error: E; | |
}; | |
type Result<T, E = Error> = Success<T> | Failure<E>; | |
// Unsound version of tryCatch | |
export async function tryCatchUnsound<T, E = Error>( | |
promise: Promise<T>, | |
): Promise<Result<T, E>> { | |
try { | |
const data = await promise; | |
return { data, error: null }; | |
} catch (error) { | |
return { data: null, error: error as E }; | |
} | |
} | |
// Fixed version of tryCatch | |
export async function tryCatchFixed<T, E = Error>( | |
fn: () => Promise<T>, | |
): Promise<Result<T, E>> { | |
try { | |
const data = await fn(); | |
return { data, error: null }; | |
} catch (error) { | |
return { data: null, error: error as E }; | |
} | |
} | |
// Example function that throws synchronously | |
function somePromiseThatThrowsSync(): Promise<string> { | |
throw new Error("Synchronous error!"); | |
return Promise.resolve("This will never run"); | |
} | |
// Example function that throws asynchronously | |
function somePromiseThatThrowsAsync(): Promise<string> { | |
return Promise.reject(new Error("Asynchronous error!")); | |
} | |
// Test the unsound version | |
async function testUnsound() { | |
console.log("Testing unsound version..."); | |
try { | |
const { data, error } = await tryCatchUnsound(somePromiseThatThrowsSync()); | |
if (error) { | |
console.error("Caught error (unsound):", error.message); | |
} else { | |
console.log("Data (unsound):", data); | |
} | |
} catch (err) { | |
// Narrow down the type of `err` before accessing `message` | |
if (err instanceof Error) { | |
console.error("Uncaught error (unsound):", err.message); | |
} else { | |
console.error("Uncaught unknown error (unsound):", err); | |
} | |
} | |
} | |
// Test the fixed version | |
async function testFixed() { | |
console.log("Testing fixed version..."); | |
try { | |
const { data, error } = await tryCatchFixed(() => somePromiseThatThrowsSync()); | |
if (error) { | |
console.error("Caught error (fixed):", error.message); | |
} else { | |
console.log("Data (fixed):", data); | |
} | |
} catch (err) { | |
// Narrow down the type of `err` before accessing `message` | |
if (err instanceof Error) { | |
console.error("Uncaught error (fixed):", err.message); | |
} else { | |
console.error("Uncaught unknown error (fixed):", err); | |
} | |
} | |
} | |
// Run tests | |
(async () => { | |
await testUnsound(); // This will crash with an uncaught error | |
await testFixed(); // This will catch the error properly | |
})(); |
Nice one. What do you recommend than? Try catch is kinda broken
The rule of them on other languages I've worked with is that every async function needs a Try/Catch
block inside it, and then you can choose to propagate the error, but generally you don't want async functions to throw an error. If the function returns a promise, you could have it return a rejected promise.
This solution just seems hackish. For every function call, you are calling through this Try/Catch
block, and then another anonymous function. It doesn't seem like the proper call path.
I would try to make sure that all async
functions return a value. Promises have a .Catch()
so the errors are designed to propagate up, but I wouldn't expect that to always be the case.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
BTW, don't do this. This is just an example on how something can be done. It's not a good idea to do this. If you find yourself rewriting core parts of the language, then you probably don't understand the language.