1/**
2 * helper functions for dealing with the `unknown` type, mainly in `catch`
3 * blocks or promise rejection callbacks.
4 *
5 * @module
6 */
7
8/** extra fields on errors are extremely helpful for debugging. */
9export interface Error extends globalThis.Error {
10 [metadata: string]: unknown;
11}
12
13/** retrieve an error message from any value */
14export function message(error: unknown): string {
15 let message = (error as { message: unknown })?.message ?? error;
16 try {
17 message = typeof message === "string"
18 ? message
19 // NOTE: typescript standard library lies here (https://github.com/mattpocock/ts-reset/pull/190)
20 : String(JSON.stringify(message) as string | undefined);
21 } catch {}
22 try {
23 return String(message);
24 } catch {}
25 return `Could not stringify error message ${typeof message}`;
26}
27
28/** retrieve an error-like object from any value. Useful to check fields. */
29export function obj(error: unknown): { message: string } & Partial<Error> {
30 if (error instanceof Error) return error as Error;
31 return {
32 message: message(error),
33 ...(typeof error === "object" && error),
34 };
35}
36
37/** node.js error codes are string values on the `.code` property. */
38export function code(error: unknown): node.ErrorCode | null {
39 const code = (error as { code: unknown })?.code;
40 return typeof code === "string" ? code : null;
41}
42
43/** attach extra fields and rethrow a value. */
44export function rethrowWithMetadata(
45 err: unknown,
46 meta: Record<string, unknown>,
47): never {
48 const error = err && typeof err === "object" ? err : new Error(message(err)); // no stack trace :/
49 Object.assign(error, meta);
50 throw error;
51}
52
53import type * as node from "./node.ts";