Skip to content

BlackGlory/extra-lazy

Repository files navigation

extra-lazy

Yet another lazy evaluation library.

Install

npm install --save extra-lazy
# or
yarn add extra-lazy

Usage

import { lazy } from 'extra-lazy'

const getValue = lazy(() => {
  // ...
  return value
})
const value = getValue()

API

lazy

function lazy<T>(getter: () => T): () => T

Create a value lazily.

which implicitly has memoization, because the evaluation will only be performed once.

weakLazy

function weakLazy<T extends object>(getter: () => T): () => T

lazyFunction

function lazyFunction<Result, Args extends any[]>(
  getter: () => (...args: Args) => Result
): (...args: Args) => Result

Create a function lazily.

lazyAsyncFunction

function lazyAsyncFunction<Result, Args extends any[]>(
  getter: () => PromiseLike<(...args: Args) => Result>
): (...args: Args) => Promise<Result>

Create a async function lazily.

lazyStatic

function lazyStatic<T>(
  getter: () => T
, deps?: unknown[] = []
): T

/**
 * @param fn
 * The function must satisfy the following conditions, it's like React hooks very much:
 * - The function should not be an async function,
 *   it is impossible to ensure that `lazyStatic` works correctly in asynchronous flows.
 * - `lazyStatic` calls should not be in loops or branches.
 */
function withLazyStatic<Result, Args extends any[]>(
  fn: (...args: Args) => Result
): (...args: Args) => Result

Example:

const fn = withLazyStatic((text: string) => lazyStatic(() => text))

fn('hello') // 'hello'
fn('world') // 'hello'

Best practices

Loop
// bad
withLazyStatic(() => {
  while (condition) {
    const value = lazyStatic(() => {
      // ...
    })
    // ...
  }
})

// good
withLazyStatic(() => {
  const value = lazyStatic(() => {
    // ...
  })

  while (condition) {
    // ...
  }
})
Branch
// bad
withLazyStatic(() => {
  if (condition) {
    const value = lazyStatic(() => {
      // ...
    })
    // ...
  } else {
    // ...
  }
})

// good
withLazyStatic(() => {
  const value = lazyStatic(() => {
    // ...
  })

  if (condition) {
    // ...
  } else {
    // ...
  }
})
Assertion/Validation
// bad
withLazyStatic((form: IForm) => {
  if (validate(form)) {
    const value = lazyStatic(() => {
      // ...
    })
    // ...
  } else {
    const value = lazyStatic(() => {
      // ...
    })
    return null // or throw an error
  }
})

// okay
withLazyStatic((form: IForm) => {
  if (validate(form)) {
    const value = lazyStatic(() => {
      // ...
    })
    // ...
  } else {
    return null // or throw an error
  }
})

// good, `lazyStatic` can always be called after guards
withLazyStatic((form: IForm) => {
  if (!validate(form)) return null // or throw an error

  const value = lazyStatic(() => {
    // ...
  })
  // ...
})