import toast from 'react-hot-toast' type ExcludeErr = Exclude /** * Similar to Error, but more lightweight, without the stack trace. It can also * be used to represent a reason for not being able to provide an alternative, * which isn't necessarily an error. */ export class Reason { message: string constructor(message: string) { this.message = message } toError() { return new Error(this.message) } } /** * This is intentionally *not* exported due to misuse. We'd like to add a lint. */ function isErr(value: ExcludeErr | Error): value is Error { return value instanceof Error } // Used to bubble errors up export function err(value: ExcludeErr | Error): value is Error { if (!isErr(value)) { return false } // TODO: Remove this once we have a lint to prevent misuse of this function. console.error(value) return true } /** Takes array of maybe error and types narrows them into * @returns [hasErr, arrayWithoutErr, arrayWithErr] */ export function cleanErrs( value: Array | Error> ): [boolean, Array>, Array] { const argsWOutErr: Array> = [] const argsWErr: Array = [] for (const v of value) { if (isErr(v)) { argsWErr.push(v) } else { argsWOutErr.push(v) } } return [argsWOutErr.length !== value.length, argsWOutErr, argsWErr] } export function report( message: string, { showToast }: { showToast: boolean } = { showToast: false } ) { console.error(message) if (showToast) { toast.error(message, { id: 'error' }) } } /** * Report a promise rejection. The type of reason is `any` so that it matches * Promise.prototype.catch. */ export function reportRejection(reason: any) { report((reason ?? 'Unknown promise rejection').toString()) } /** * Report an error to the user. Trapping is the opposite of propagating an * error. We should propagate errors in low-level functions and trap at the top * level. */ export function trap( value: ExcludeErr | Error, opts?: { altErr?: Error suppress?: boolean } ): value is Error { if (!isErr(value)) { return false } console.error(value) opts?.suppress || toast.error((opts?.altErr ?? value ?? new Error('Unknown')).toString(), { id: 'error', }) return true } export function reject(errOrString: Error | string): Promise { return Promise.reject(errOrString) }