Sometimes, suppressing errors is handy.
E.g. you see this:
try { scrollableRef.update() } catch {}
Let's create something to handle this in a cleaner fashion. We'll use a functional style that prefers wrap functions to extend functionality.
We "wrap" a function with error handling, returning a function with an identical signature:
import { isPromise } from '@tool-belt/type-predicates'; /** * Wraps a function with error suppression and optional logging. * * @param fn - The function to execute. * @param errorMessage - The error message to log if an exception is thrown. * @returns The wrapped function with error suppression. */ export function withSuppress<T extends (...args: any[]) => any>( fn: T, errorMessage?: string, ): (...args: Parameters<T>) => ReturnType<T> extends Promise<infer U> ? Promise<U | undefined> : ReturnType<T> | undefined { const log = errorMessage ? (msg: string) => console.error(msg) : null; return (...args: Parameters<T>) => { try { const result = fn(...args); if (isPromise(result)) { return result.catch((error) => { log?.(`${errorMessage}\n${error?.stack ?? error}`); return undefined; }) as ReturnType<T> extends Promise<infer U> ? Promise<U | undefined> : never; } return result; } catch (error) { log?.(`${errorMessage}\n${error?.stack ?? error}`); return undefined; } }; }
And now we can suppress errors elegantly.
Here are some example uses:
# generate content
Here is a Vitest test suite for the function:
import { withSuppress } from './functional'; describe('withSuppress', () => { it('should return the value from a synchronous function without errors', () => { const syncFn = () => 42; const wrappedFn = withSuppress(syncFn); expect(wrappedFn()).toBe(42); }); it('should return undefined and log error when synchronous function throws', () => { const errorMessage = 'Sync error occurred'; const syncFn = () => { throw new Error('Test Error'); }; const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); const wrappedFn = withSuppress(syncFn, errorMessage); expect(wrappedFn()).toBeUndefined(); expect(consoleErrorSpy).toHaveBeenCalledWith( expect.stringContaining(`${errorMessage}\nError: Test Error`), ); consoleErrorSpy.mockRestore(); }); it('should return the resolved value from an asynchronous function without errors', async () => { const asyncFn = async () => await Promise.resolve(42); const wrappedFn = withSuppress(asyncFn); await expect(wrappedFn()).resolves.toBe(42); }); it('should return undefined and log error when asynchronous function rejects', async () => { const errorMessage = 'Async error occurred'; const asyncFn = async () => await Promise.reject(new Error('Test Error')); const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); const wrappedFn = withSuppress(asyncFn, errorMessage); await expect(wrappedFn()).resolves.toBeUndefined(); expect(consoleErrorSpy).toHaveBeenCalledWith( expect.stringContaining(`${errorMessage}\nError: Test Error`), ); consoleErrorSpy.mockRestore(); }); it('should return undefined if no error message is provided and the function throws', () => { const syncFn = () => { throw new Error('Test Error'); }; const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); const wrappedFn = withSuppress(syncFn); expect(wrappedFn()).toBeUndefined(); expect(consoleErrorSpy).not.toHaveBeenCalled(); consoleErrorSpy.mockRestore(); }); it('should return undefined if no error message is provided and the async function rejects', async () => { const asyncFn = async () => await Promise.reject(new Error('Test Error')); const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); const wrappedFn = withSuppress(asyncFn); await expect(wrappedFn()).resolves.toBeUndefined(); expect(consoleErrorSpy).not.toHaveBeenCalled(); consoleErrorSpy.mockRestore(); }); it('should handle functions that return promises without errors', async () => { const asyncFn = async () => await Promise.resolve('async result'); const wrappedFn = withSuppress(asyncFn); await expect(wrappedFn()).resolves.toBe('async result'); }); it('should handle synchronous functions returning undefined without errors', () => { const syncFn = () => undefined; const wrappedFn = withSuppress(syncFn); expect(wrappedFn()).toBeUndefined(); }); });
Top comments (0)