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: PropertyKey]: 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 =
18 typeof message === "string"
19 ? message
20 : // NOTE: typescript standard library lies here (https://github.com/mattpocock/ts-reset/pull/190)
21 String(JSON.stringify(message) as string | undefined);
22 } catch {}
23 try {
24 return String(message);
25 } catch {}
26 return `Could not stringify error message ${typeof message}`;
27}
28
29/** retrieve an error-like object from any value. Useful to check fields. */
30export function obj(error: unknown): { message: string } & Partial<Error> {
31 if (error instanceof Error) return error as Error;
32 return {
33 message: message(error),
34 ...(typeof error === "object" && error),
35 };
36}
37
38/** node.js error codes are string values on the `.code` property. */
39export function code(error: unknown): node.ErrorCode | null {
40 const code = (error as { code: unknown })?.code;
41 return typeof code === "string" ? code : null;
42}
43
44/** attach extra fields and rethrow a value. */
45export function rethrowWithMetadata(err: unknown, meta: Record<string, unknown>): never {
46 const error = err && typeof err === "object" ? err : new Error(message(err)); // no stack trace :/
47 Object.assign(error, meta);
48 throw error;
49}
50
51import type * as node from "./node.ts";