Skip to content

Commit

Permalink
feat: add TypeScript types
Browse files Browse the repository at this point in the history
  • Loading branch information
Marsup committed May 25, 2022
1 parent 87228f0 commit 9136ed5
Show file tree
Hide file tree
Showing 3 changed files with 288 additions and 2 deletions.
124 changes: 124 additions & 0 deletions lib/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import type { Boom } from "@hapi/boom";
import type { AssertionError } from "assert";

export type BounceErrorType = Error | "system" | "boom" | Record<any, any>;

export interface BounceOptions {
/**
* An object which is assigned to the `err`, copying the properties onto the error.
*/
decorate?: Record<any, any>;

/**
* An error used to override `err` when `err` matches. If used with `decorate`, the `override` object is modified.
*/
override?: Error;

/**
* If `true`, the error is returned instead of thrown. Defaults to `false`.
* @defaultValue `false`
*/
return?: boolean;
}

/**
* A single item or an array of items of:
* - An error constructor (e.g. `SyntaxError`).
* - `'system'` - matches any languange native error or node assertions.
* - `'boom'` - matches [**boom**](https://github.com/hapijs/boom) errors.
* - an object where each property is compared with the error and must match the error property
* value. All the properties in the object must match the error but do not need to include all
* the error properties.
*/
export type BounceErrorTypes = BounceErrorType | BounceErrorType[];

export type BounceReturn<
TErr extends Error,
TOpts extends BounceOptions
> = TOpts extends { return: true }
? TOpts extends { decorate: any }
? (TOpts extends { override: any } ? TOpts["override"] : TErr) &
TOpts["decorate"]
: TOpts extends { override: any }
? TOpts["override"]
: TErr
: void;

/**
* Throws the error passed if it matches any of the specified rules where:
* - `err` - the error.
*
* @param err The error.
* @param types {@link BounceErrorTypes}
* @param options {@link BounceOptions}
*/
export function rethrow<TErr extends Error, TOpts extends BounceOptions>(
err: TErr,
types: BounceErrorTypes,
options?: TOpts
): BounceReturn<TErr, TOpts>;

/**
* The opposite action of {@link rethrow `rethrow()`}. Ignores any errors matching the specified `types`. Any error not matching is thrown after applying the `options`.
*
* @param err The error.
* @param types same as the {@link BounceErrorTypes `types`} argument passed to `rethrow()`
* @param options same as the {@link BounceOptions `options`} argument passed to `rethrow()`
*/
export function ignore<TErr extends Error, TOpts extends BounceOptions>(
err: TErr,
types: BounceErrorTypes,
options?: TOpts
): BounceReturn<TErr, TOpts>;

/**
* Awaits for the value to resolve in the background and then apply either the `rethrow()` or `ignore()` actions.
*
* @param operation a function, promise, or value that is `await`ed on inside a `try...catch` and any error thrown processed by the `action` rule.
* @param action one of `'rethrow'` or `'ignore'`. Defaults to `'rethrow'`.
* @param types same as the `types` argument passed to `rethrow()` or `ignore()`. Defaults to `'system'`.
* @param options same as the {@link BounceOptions `options`} argument passed to `rethrow()` or `ignore()`.
*/
export function background(
operation: Function | Promise<any> | any,
action?: "rethrow" | "ignore",
types?: BounceErrorTypes,
options?: BounceOptions
): Promise<void>;

/**
* Returns `true` when `err` is a [**boom**](https://github.com/hapijs/boom) error.
*
* @param err The error.
*/
export function isBoom(err: unknown): err is Boom;

/**
* Returns `true` when `err` is an error.
*
* @param err The error.
*/
export function isError(err: unknown): err is Error;

/**
* Return `true` when `err` is one of:
* - `EvalError`
* - `RangeError`
* - `ReferenceError`
* - `SyntaxError`
* - `TypeError`
* - `URIError`
* - Node's `AssertionError`
*
* @param err The error.
*/
export function isSystem(
err: unknown
): err is
| EvalError
| RangeError
| ReferenceError
| SyntaxError
| TypeError
| URIError
| AssertionError;
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"version": "3.0.0",
"repository": "git://github.com/hapijs/bounce",
"main": "lib/index.js",
"types": "lib/index.d.ts",
"files": [
"lib"
],
Expand All @@ -23,10 +24,11 @@
"devDependencies": {
"@hapi/code": "^9.0.0",
"@hapi/eslint-plugin": "*",
"@hapi/lab": "25.0.0-beta.1"
"@hapi/lab": "^25.0.1",
"typescript": "^4.7.2"
},
"scripts": {
"test": "lab -a @hapi/code -t 100 -L",
"test": "lab -a @hapi/code -t 100 -L -Y",
"test-cov-html": "lab -a @hapi/code -r html -o coverage.html -L"
},
"license": "BSD-3-Clause"
Expand Down
160 changes: 160 additions & 0 deletions test/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import * as Bounce from "..";
import * as Lab from "@hapi/lab";

const { expect } = Lab.types;

class CustomErr extends Error {
customProp = "customProp";
}

// rethrow
expect.type<void>(Bounce.rethrow(new Error(), "system"));
expect.type<void>(Bounce.rethrow(new Error(), "boom"));
expect.type<void>(Bounce.rethrow(new Error(), ["system", "boom"]));
expect.type<void>(Bounce.rethrow(new Error(), { prop: "prop" }));
expect.type<void>(
Bounce.rethrow(new Error(), "system", { decorate: { prop: "prop" } })
);
expect.type<void>(
Bounce.rethrow(new Error(), "system", {
decorate: { prop: "prop" },
override: new CustomErr(),
})
);
expect.type<CustomErr & { prop: string }>(
Bounce.rethrow(new Error(), "system", {
decorate: { prop: "prop" },
override: new CustomErr(),
return: true,
})
);
expect.type<CustomErr>(
Bounce.rethrow(new Error(), "system", {
override: new CustomErr(),
return: true,
})
);
expect.type<Error>(Bounce.rethrow(new Error(), "system", { return: true }));
expect.type<Error & { prop: string }>(
Bounce.rethrow(new Error(), "system", {
decorate: { prop: "prop" },
return: true,
})
);

expect.error(Bounce.rethrow(new Error(), "systm"));
expect.error(Bounce.rethrow(new Error(), "bom"));
expect.error(Bounce.rethrow(new Error(), ["system", "bom"]));
expect.error(Bounce.rethrow(new Error(), "system", { decorate: true }));
expect.error(
Bounce.rethrow(new Error(), "system", { override: { prop: "prop" } })
);
expect.error(Bounce.rethrow(new Error(), "system", { return: 1 }));

// ignore
expect.type<void>(Bounce.ignore(new Error(), "system"));
expect.type<void>(Bounce.ignore(new Error(), "boom"));
expect.type<void>(Bounce.ignore(new Error(), { prop: "prop" }));
expect.type<void>(
Bounce.ignore(new Error(), "system", { decorate: { prop: "prop" } })
);
expect.type<void>(
Bounce.ignore(new Error(), "system", {
decorate: { prop: "prop" },
override: new CustomErr(),
})
);
expect.type<CustomErr & { prop: string }>(
Bounce.ignore(new Error(), "system", {
decorate: { prop: "prop" },
override: new CustomErr(),
return: true,
})
);
expect.type<CustomErr>(
Bounce.ignore(new Error(), "system", {
override: new CustomErr(),
return: true,
})
);
expect.type<Error>(Bounce.ignore(new Error(), "system", { return: true }));
expect.type<Error & { prop: string }>(
Bounce.ignore(new Error(), "system", {
decorate: { prop: "prop" },
return: true,
})
);

expect.error(Bounce.ignore(new Error(), "systm"));
expect.error(Bounce.ignore(new Error(), "bom"));
expect.error(Bounce.ignore(new Error(), "system", { decorate: true }));
expect.error(
Bounce.ignore(new Error(), "system", { override: { prop: "prop" } })
);
expect.error(Bounce.ignore(new Error(), "system", { return: 1 }));

// background
expect.type<Promise<void>>(Bounce.background(() => {}));
expect.type<Promise<void>>(Bounce.background(() => {}, "rethrow"));
expect.type<Promise<void>>(Bounce.background(() => {}, "ignore"));
expect.type<Promise<void>>(Bounce.background(() => {}, "rethrow", "system"));
expect.type<Promise<void>>(Bounce.background(() => {}, "rethrow", "boom"));
expect.type<Promise<void>>(
Bounce.background(() => {}, "rethrow", { prop: "prop" })
);
expect.type<Promise<void>>(
Bounce.background(() => {}, "rethrow", "system", {
decorate: { prop: "prop" },
})
);
expect.type<Promise<void>>(
Bounce.background(() => {}, "rethrow", "system", {
decorate: { prop: "prop" },
override: new CustomErr(),
})
);
expect.type<Promise<void>>(
Bounce.background(() => {}, "rethrow", "system", {
decorate: { prop: "prop" },
override: new CustomErr(),
return: true,
})
);
expect.type<Promise<void>>(
Bounce.background(() => {}, "rethrow", "system", {
override: new CustomErr(),
return: true,
})
);
expect.type<Promise<void>>(
Bounce.background(() => {}, "rethrow", "system", { return: true })
);
expect.type<Promise<void>>(
Bounce.background(() => {}, "rethrow", "system", {
decorate: { prop: "prop" },
return: true,
})
);

expect.error(Bounce.background(() => {}, "rethro"));
expect.error(Bounce.background(() => {}, "ignor"));
expect.error(Bounce.background(() => {}, "rethrow", "systm"));
expect.error(Bounce.background(() => {}, "rethrow", "bom"));
expect.error(
Bounce.background(() => {}, "rethrow", "system", { decorate: true })
);
expect.error(
Bounce.background(() => {}, "rethrow", "system", {
override: { prop: "prop" },
})
);
expect.error(Bounce.background(() => {}, "rethrow", "system", { return: 1 }));

// isBoom
expect.type<boolean>(Bounce.isBoom(""));

// isError
expect.type<boolean>(Bounce.isError(""));

// isSystem
expect.type<boolean>(Bounce.isError(""));

0 comments on commit 9136ed5

Please sign in to comment.