Skip to content

Commit

Permalink
refactor: Add rethrow_unless util for try/catch blocks (#243)
Browse files Browse the repository at this point in the history
Add a custom type-safe util that ensures an error matches an expected
type, otherwise rethrows. Just cleans up some logic with fallback logic
and `NodeNotFoundError`.
  • Loading branch information
manzt authored Jan 7, 2025
1 parent 2543a01 commit 7832f80
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 12 deletions.
14 changes: 8 additions & 6 deletions packages/core/src/consolidated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ import type {
GroupMetadata,
GroupMetadataV2,
} from "./metadata.js";
import { json_decode_object, json_encode_object } from "./util.js";
import {
json_decode_object,
json_encode_object,
rethrow_unless,
} from "./util.js";

type ConsolidatedMetadata = {
metadata: Record<string, ArrayMetadataV2 | GroupMetadataV2>;
Expand Down Expand Up @@ -134,10 +138,8 @@ export async function withConsolidated<Store extends Readable>(
export async function tryWithConsolidated<Store extends Readable>(
store: Store,
): Promise<Listable<Store> | Store> {
return withConsolidated(store).catch((e: unknown) => {
if (e instanceof NodeNotFoundError) {
return store;
}
throw e;
return withConsolidated(store).catch((error: unknown) => {
rethrow_unless(error, NodeNotFoundError);
return store;
});
}
11 changes: 5 additions & 6 deletions packages/core/src/open.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type {
import {
ensure_correct_scalar,
json_decode_object,
rethrow_unless,
v2_to_v3_array_metadata,
v2_to_v3_group_metadata,
} from "./util.js";
Expand Down Expand Up @@ -64,8 +65,8 @@ async function open_v2<Store extends Readable>(
if (options.kind === "array") return open_array_v2(loc, attrs);
if (options.kind === "group") return open_group_v2(loc, attrs);
return open_array_v2(loc, attrs).catch((err) => {
if (err instanceof NodeNotFoundError) return open_group_v2(loc, attrs);
throw err;
rethrow_unless(err, NodeNotFoundError);
return open_group_v2(loc, attrs);
});
}

Expand Down Expand Up @@ -192,10 +193,8 @@ export async function open<Store extends Readable>(
let open_primary = version_max === "v2" ? open.v2 : open.v3;
let open_secondary = version_max === "v2" ? open.v3 : open.v2;
return open_primary(location, options).catch((err) => {
if (err instanceof NodeNotFoundError) {
return open_secondary(location, options);
}
throw err;
rethrow_unless(err, NodeNotFoundError);
return open_secondary(location, options);
});
}

Expand Down
40 changes: 40 additions & 0 deletions packages/core/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -292,3 +292,43 @@ export function ensure_correct_scalar<D extends DataType>(
}
return metadata.fill_value;
}

// biome-ignore lint/suspicious/noExplicitAny: Necessary for type inference
type InstanceType<T> = T extends new (...args: any[]) => infer R ? R : never;

// biome-ignore lint/suspicious/noExplicitAny: Abstract base type
type ErrorConstructor = new (...args: any[]) => Error;

/**
* 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.
*
* @see {@link https://gist.github.com/manzt/3702f19abb714e21c22ce48851c75abf}
*
* @example
* ```ts
* class DatabaseError extends Error { }
* class NetworkError extends Error { }
*
* try {
* await db.query();
* } catch (err) {
* rethrow_unless(err, DatabaseError, NetworkError);
* err // DatabaseError | NetworkError
* }
* ```
*
* @param error - The error to check
* @param errors - Expected error type(s)
* @throws The original error if it doesn't match expected type(s)
*/
export function rethrow_unless<E extends ReadonlyArray<ErrorConstructor>>(
error: unknown,
...errors: E
): asserts error is InstanceType<E[number]> {
if (!errors.some((ErrorClass) => error instanceof ErrorClass)) {
throw error;
}
}

0 comments on commit 7832f80

Please sign in to comment.