stdlazy
Version:
Flexible and debuggable lazy primitive.
71 lines (66 loc) • 2.98 kB
text/typescript
import { Lazy, ownerInstance } from "./lazy"
import { LazyAsync, Pulled } from "./types"
/**
* Creates a lazy primitive around the given function, making sure it's only executed once. Works
* for both synchronous and asynchronous evaluation.
*
* @example
* // Simple initializer:
* const regular = lazy(() => 1) satisfies Lazy<number>
*
* // Initializer returning another lazily primitive is flattened:
* const lazyNested = lazy(() => lazy(() => 1)) satisfies Lazy<number>
*
* // Async initializer gives a `LazyAsync` instance:
* const lazyAsync = lazy(async () => 1) satisfies LazyAsync<number>
*
* // Async initializer returning another lazily primitive is flattened:
* const asyncLazy = lazy(async () => lazy(() => 1)) satisfies LazyAsync<number>
*
* // Async initializer returning another lazily async primitive is flattened:
* const asyncLazyAsync = lazy(async () => lazy(async () => 1)) satisfies LazyAsync<number>
*
* @param initializer An initializer function that will be executed once to produce the value. Can
* be synchronous or asynchronous and will also handle nested lazy primitives.
*/
export function lazy<X>(initializer: () => Promise<LazyAsync<X>>): LazyAsync<X>
export function lazy<X>(initializer: () => Promise<Lazy<X>>): LazyAsync<X>
export function lazy<X>(initializer: () => Promise<X>): LazyAsync<X>
export function lazy<T>(initializer: () => Lazy<T>): Lazy<T>
export function lazy<T>(initializer: () => T): Lazy<T>
export function lazy<T>(initializer: () => T | Lazy<T>): Lazy<T> {
return Lazy.create(initializer) as any
}
/**
* Memoizes the given function, caching its result and making sure it's only executed once. Uses
* {@link Lazy} under the hood.
*
* @example
* // Synchronous memoization:
* let count = 0
* const func = () => count++
* const memFunc = memoize(func) satisfies () => number
* memFunc() // 0
* memFunc() // 0
* // Asynchronous memoization:
* let count = 0
* const func = async () => count++
* const memFunc = memoize(func) satisfies () => Promise<number>
* await memFunc() // 0
*
* @param definition The function to memoize. It can be synchronous, asynchronous, or return a lazy
* primitive.
* @returns A function that will execute the memoized function and return its result.
*/
export function memoize<T>(definition: 0 extends 1 & T ? any : never): () => any
export function memoize<T extends Lazy<Promise<any>>>(definition: () => T): () => Pulled<T>
export function memoize<T extends Lazy<Promise<any>>>(definition: () => T): () => Pulled<T>
export function memoize<T extends Lazy<any>>(definition: () => T): () => Pulled<T>
export function memoize<T>(definition: () => T): () => T
export function memoize<T>(definition: () => T): () => T {
// Don't double memoize
if (ownerInstance in definition) {
return definition as any
}
return lazy(definition).pull as any
}