2.0.0 • Published 1 year ago

build-a-promise v2.0.0

Weekly downloads
-
License
ISC
Repository
github
Last release
1 year ago

build-a-promise

Creates a promise that uses the builder-pattern. The chained functions will run asynchronously.

npm i build-a-promise  |  pnpm add build-a-promise

Try it out in TypeScript Playground

Example

Minimal example

import builder from 'build-a-promise'

const test = builder(r => (s: number, k: boolean) => {
    console.log('Initial: ', {s,k})
    // * Initial code (cannot be run asynchronously)

    let i = 0
    return {
        __build() {
            console.log('build')
            return 'test-result' as const
        },
        async __init() {
            // * Initial code (can be async)
            console.log('__init')
        },
        __step() {
            console.log('step')
        },
        i: (str: string) => {
            console.log(i, str)
            i++
        }
    }
})

async function testFunction() {
    const returnedValue: 'test-result' = await test(2, true).i('test').i('asd').i('herpderp')
    console.log({returnedValue})
}

testFunction()

/*
    Console
    -----------
    Initial:  {s: 2, k: true}
    __init
    0 'test'
    step
    1 'asd'
    step
    2 'herpderp'
    step
    build
    {returnedValue: 'test-result'}
*/

Usage

The builder has two callbacks e.g.

const pizza = builder(r => () => {
    // * Initial code
})

r: If you want to resolve or reject the promise early, they're provided there.

const pizza = builder(({resolve, reject}) => () => {
    // * Initial code
})

Next callback is the initial parameters provided the to function.

const pizza = builder(r => (pizzaType: string) => {
    // * Initial code
})
...
await pizza('mexican')

Last thing you need to know, is that you return an object.

The object requires __build, which will "build" the promise. The returned value of build, will define what type the promise returns.

const pizza = builder(r => (pizzaType: string) => {
    // * Initial code
    const extras = {
        cheese = 0
    }
    return {
        __build() {
            return extras
        },
        extraCheese() {
            extras.cheese++
        }
    }
})
...
const finishedPizza = await pizza('mexican').extraCheese().extraCheese()
//    ^? finishedPizza = { cheese: number }

The returned values from functions

ANY function (both chained functions and builder options e.g. __) may provide a returned value.

If a function returns a value - it will be equivilant to resolve(value).

The difference being, returning a value will also provide a type.

Exceptions:

  • The returned value of __catch will be equivilant to reject(value)
  • __finally cannot return anything

Note: If __build returns void, the returned type is Promise<undefined | Others> - where Others are the returned types from other functions.

As a Function

You can also return a function, if you provide a third callback:

const pizza = builder(r => (pizzaType: string) => (...args) => {
   ... 
})

pizza('mexican')(...args)
pizza('mexican').extraCheese().extraCheese()(...args)

Builder functions

Order of execution: __init → (__step)__build__finally

NameDescription
__init?.()The initial function to be called. Used to initialize values that require asynchronous operatinos.Like the other declared functions here, it will be called without chaining it.
__catch?.(error)The whole chain is inside a try-catch block. If an error occurs, and catch is defined, rather than throwing the error, catch will be called.Note: If __catch is not defined, reject(error), will be called before throwing an error.
__step?.()Runs after each step in the chain functions. Good for things like validating every step.
__build?.()Is called as a last function to be called (before finally). This returns the awaited result of the builder-pattern. It is optional - as sometimes we just want to run a chain of commands without a final "build".
__finally?.()The last function - and will always run. Consider it as a way to clean-up after the full execution.