Skip to content

Function: fallbackIfFails()

fallbackIfFails<T, TArgs, TFB, TFBVal, Result>(target, args, fallback): Result

Defined in: packages/core/src/fallbackIfFails.ts:108

fallbackIfFails

Type Parameters

T

T

TArgs

TArgs extends unknown[] = unknown[]

TFB

TFB = T

TFBVal

TFBVal = TFB extends (...args) => V ? V : TFB

Result

Result = T extends Promise<unknown> ? true : never extends never ? T | TFBVal : Promise<Awaited<T> | Awaited<TFBVal>>

Parameters

target

promise or function to execute

T | (...args) => T

args

arguments to be supplied to func fuction

TArgs | () => TArgs

fallback

alternative value to be used when target throws error.

  • If fallback is a function and it raises exception, it will cause to raise an exception instead of gracefully ignoring it. A fallback of the fallback function is out of the scope of fallbackIfFails. However, the fallback function can still be wrapped inside a secondary fallbackIfFails. See the "Fallback chaining" example below.
  • If target a promise or async function, fallback can be either be a value, a promise or an async function.

IfPromiseAddValue<TFB> | (reason) => IfPromiseAddValue<TFB>

Returns

Result

A Promise is returned if the target is a Promise or returns one. Otherwise, the direct value is returned.

Examples

Async functions: working with async functions or functions that returns a promise

typescript
import { fallbackIfFails } from '@superutils/core'

const args = ['some value', true]
const ensureValue = async (value: string, criteria?: boolean) => {
    if (criteria !== false && !value.trim()) throw new Error('No value. Should use fallback value')
    return value
}
// This makes sure there's always a value without having to manually write try-catch block.
const value = await fallbackIfFails(
    ensureValue,
    () => args as Parameters<typeof ensureValue>,
    async () => 'fallback value'
)
console.log({ value }) // 'some value'

Non-async functions: working synchronous function that returns value synchronously

typescript
import { fallbackIfFails } from '@superutils/core'

const args = ['some value', true]
const ensureValue = (value: string, criteria?: boolean) => {
    if (criteria !== false && !value.trim()) throw new Error('No value. Should use fallback value')
    return value
}
// this makes sure there's always a value without having to manually write try-catch block.
const value = fallbackIfFails(
    ensureValue,
    () => args as Parameters<typeof ensureValue>,
    () => 'fallback value'
)
console.log({ value }) // 'some value'

Hybrid functions: working with function that returns value sync/async circumstantially

javascript
import { fallbackIfFails } from '@superutils/core'

const getData = (useCache = true, cacheKey = 'data-cache') => {
    if (useCache && localStorage[cacheKey]) return localStorage[cacheKey]
    return fetch('[DUMMYJSON-DOT-COM]/productsi')
        .then(r => r.json())
        .then(data => {
		       if(cacheKey) localStorage[cacheKey] = data
            return data
        })
}
// First call: no cache, will execute fetch and return a promise
const first = await fallbackIfFails(getData, [false], { fallback: true })
console.log({ first }) // { fallback: true }

// Second call: cache available and will return data synchronously
const second = fallbackIfFails(getData, [true], { fallback: true })
console.log({ second }) // { fallback: true }

Fallback-chaining: gracefully handle the fallback function

javascript
import { fallbackIfFails } from '@superutils/core'

const target = () => {
    if (new Date().getTime() > 0) throw new Error('I will raise error')
}
const fallback = () => {
    throw new Error('I will also raise an exception')
}
const value = fallbackIfFails(
    target,
    [],
	   // this function will only be invoked when
    () => fallbackIfFails(fallback, [], 'fallback')
)

console.log({ value }) // 'fallback'