Last active
July 10, 2025 08:53
-
-
Save joggienl/675f97011c99248d479845a1709b72d8 to your computer and use it in GitHub Desktop.
π― TypeScript Promise Error Handling Utility
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
/** | |
* tryCatch - Go-style error handling for JavaScript Promises | |
* | |
* A utility function that bridges Promise-based and tuple-based error handling. | |
* Perfect for avoiding try-catch blocks while maintaining explicit error handling. | |
* | |
* @author Jogchum Koerts | |
* @version 2.0.0 | |
* @created 2025-07-09 | |
* @license MIT | |
* | |
* Usage: | |
* 1. Copy this file to your project's utils folder | |
* 2. Import: import { tryCatch } from './utils/tryCatch' | |
* 3. Use: const [data, error] = await tryCatch(somePromise) | |
* | |
* Linter Note: | |
* Some linters may suggest converting this to an async function. We intentionally use | |
* .then()/.catch() here for semantic consistency - this utility wraps Promises, so using Promise | |
* methods feels more natural than async/await syntax. | |
* | |
* File-level disable examples: | |
* - ESLint: `// eslint-disable @typescript-eslint/promise-function-async` | |
* - Biome: `// biome-ignore lint/suspicious/noAsyncPromiseExecutor: semantic consistency` | |
* | |
* GitHub Gist: https://gist.github.com/joggienl/675f97011c99248d479845a1709b72d8 | |
*/ | |
// You can add the linter disable line here if you need... | |
/** | |
* Handles and catches specific types of errors from a promise, returning a tuple-based result. | |
* | |
* This function bridges the gap between JavaScript's Promise-based error handling and | |
* tuple-based error handling patterns (similar to Go's `result, err` approach). It follows | |
* the data-first convention established by JavaScript Promises, where success values take | |
* precedence over error handling. | |
* | |
* @param promise A promise that resolves to a value of type T. | |
* @param errorsToCatch An optional array of error constructors to catch. If not provided, catches | |
* all errors. If provided, only catches errors that are instances of the | |
* specified error classes. | |
* @returns A promise that resolves to either: | |
* - A 2-element tuple `[T, null]` in case of success, where T is the resolved value | |
* - A 2-element tuple `[null, InstanceType<E>]` in case of error, where E is the error type | |
* @throws If `errorsToCatch` is provided and the error is not an instance of any specified error | |
* class, the original error is re-thrown. | |
* | |
* @example | |
* ```typescript | |
* // Basic usage - catches all errors | |
* const [data, error] = await tryCatch(fetchUserData()); | |
* if (error) { | |
* console.error('Failed to fetch user:', error); | |
* return; | |
* } | |
* console.log('User data:', data); | |
* ``` | |
* | |
* @example | |
* ```typescript | |
* // Catch specific error types only | |
* const [result, error] = await tryCatch( | |
* riskyOperation(), | |
* [ValidationError, NetworkError] | |
* ); | |
* if (error) { | |
* // Handle only ValidationError or NetworkError | |
* handleKnownError(error); | |
* } | |
* // Other errors will be thrown normally | |
* ``` | |
* | |
* @example | |
* ```typescript | |
* // Functional error handling pattern | |
* const [users, fetchError] = await tryCatch(api.getUsers()); | |
* const [posts, postError] = await tryCatch(api.getPosts()); | |
* | |
* if (fetchError || postError) { | |
* return handleErrors({ fetchError, postError }); | |
* } | |
* | |
* return { users, posts }; | |
* ``` | |
*/ | |
function tryCatch<T, E extends new (message?: string) => Error>( | |
promise: Promise<T>, | |
errorsToCatch?: E[], | |
): Promise<[T, null] | [null, InstanceType<E>]> { | |
return promise | |
.then(data => [data, null] as [T, null]) | |
.catch(error => { | |
if (errorsToCatch == undefined) { | |
return [null, error] | |
} | |
if (errorsToCatch.some(errorClass => error instanceof errorClass)) { | |
return [null, error] | |
} | |
throw error | |
}) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment