@3fv/guard
Version:
TypeScript guard suite
79 lines (61 loc) • 2.25 kB
text/typescript
import { isNil, isPromise } from "./guards/primitive.js"
import type { ErrorHandler } from "./types"
export type GuardErrorHandler = (err:Error) => void
let globalErrorHandler:GuardErrorHandler | null
export function setGuardErrorHandler(errorHandler:GuardErrorHandler | null = null) {
globalErrorHandler = errorHandler
}
export type ReturnTypeOrAny<Fn extends () => any> = (ReturnType<Fn> extends never ? unknown : ReturnType<Fn>)
/**
* Get a value in a guarded fashion
* ensuring no exception
*
* @param fn
* @param defaultValue
* @returns {any}
* @param errorHandler
*/
export function getValue<Fn extends () => any, T extends ReturnType<Fn> >(
fn:Fn,
defaultValue: T = undefined,
errorHandler: ErrorHandler = globalErrorHandler
):T extends Promise<infer T2> ? Promise<T2> : T {
let result = null
try {
result = fn()
if (isPromise(result))
return result
.catch(err => {
if (errorHandler)
errorHandler(err)
return defaultValue
})
.then(value => isNil(value) ? defaultValue : value) as any
} catch (err) {
if (errorHandler)
errorHandler(err)
}
return isNil(result) ?
defaultValue : result
}
export type GuardFn = <Fn extends () => any, T extends ReturnType<Fn> >(fn:Fn, localErrorHandler?: GuardErrorHandler | null) => (void | Promise<void>)
export type GuardTool = GuardFn & {
lift: <T>(fn:() => T, localErrorHandler?: GuardErrorHandler | null) => ((fn:() => T, localErrorHandler?: GuardErrorHandler | null) => (void | Promise<void>))
}
/**
* Execute a function guarded from exception
*
* @param fn
* @param localErrorHandler
* @returns {(fn:()=>any)=>(fn:()=>any)=>any}
*/
const guardFn:GuardFn = <Fn extends () => any, T extends ReturnType<Fn> >(fn:Fn, localErrorHandler: ((err: Error) => void) | null = null):void | Promise<void> => {
const value = getValue<Fn,T>(fn, undefined, localErrorHandler)
if (isPromise(value))
return value.then(() => undefined as void)
}
export const guard: GuardTool = Object.assign(guardFn, {
lift: <Fn extends () => any, T extends ReturnType<Fn> >(fn:Fn, localErrorHandler?: GuardErrorHandler | null) =>
(fn:Fn, localErrorHandler?: GuardErrorHandler | null): (void | Promise<void>) =>
guardFn<Fn,T>(fn,localErrorHandler)
})