Last active
January 7, 2025 16:06
-
-
Save manzt/3702f19abb714e21c22ce48851c75abf to your computer and use it in GitHub Desktop.
This file contains 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
// Copyright (c) 2024 Trevor Manz - MIT License | |
/** | |
* Type-safe error handling utilities inspired by Python's try/except. | |
* | |
* @module | |
*/ | |
// deno-lint-ignore no-explicit-any | |
type InstanceType<T> = T extends new (...args: any[]) => infer R ? R : never; | |
// deno-lint-ignore no-explicit-any | |
type UnionInstanceType<T extends readonly (new (...args: any[]) => any)[]> = | |
InstanceType<T[number]>; | |
/** | |
* Ensures an error matches expected type(s), otherwise rethrows. | |
* | |
* Unmatched errors bubble up, like Python's `except`. Narrows error types for | |
* type-safe property access. | |
* | |
* @example Catch specific error | |
* ```ts | |
* class NotFoundError extends Error { | |
* getStatus() { return 404 } | |
* } | |
* | |
* try { | |
* // This will bubble up since it's not a NotFoundError | |
* throw new Error("Unexpected error"); | |
* } catch (err) { | |
* except(err, NotFoundError); | |
* // Only NotFoundError reaches here | |
* err.getStatus(); | |
* } | |
* ``` | |
* | |
* @example Handle multiple error types | |
* ```ts | |
* class DbError extends Error { | |
* query: string; | |
* } | |
* class NetworkError extends Error { | |
* code: number; | |
* } | |
* | |
* try { | |
* await db.query(); | |
* } catch (err) { | |
* except(err, DbError, NetworkError); | |
* // Only DbError or NetworkError reach here | |
* if (err instanceof DbError) { | |
* console.log(err.query); | |
* } else { | |
* console.log(err.code); | |
* } | |
* } | |
* ``` | |
* | |
* @param error - The error to check | |
* @param errorClasses - Expected error type(s) | |
* @throws The original error if it doesn't match expected type(s) | |
*/ | |
export function except< | |
// deno-lint-ignore no-explicit-any | |
ErrorClasses extends readonly (new (...args: any[]) => Error)[], | |
>( | |
error: unknown, | |
...errorClasses: ErrorClasses | |
): asserts error is UnionInstanceType<ErrorClasses> { | |
if (!errorClasses.some((ErrorClass) => error instanceof ErrorClass)) { | |
throw error; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment