UNPKG

stdlazy

Version:

Flexible and debuggable lazy primitive.

166 lines 8.36 kB
import { LazyAsync, LazyInfo, Pullable, Pulled, PulledAwaited, type _IterationType } from "./types"; export declare const methodName: unique symbol; export declare const ownerInstance: unique symbol; /** * A TypeScript-first lazy evaluation primitive. A {@link Pullable} that will only evaluate its * initializer function when the {@link pull} method is called. * * The initializer can return another {@link Lazy}, which will be chained like a promise. */ export declare class Lazy<T> implements Pullable<T>, Iterable<_IterationType<T>>, AsyncIterable<_IterationType<T>> { /** The cached value or error, stored from a previous execution of the initializer. */ private _cached?; private _desc; private _info; get info(): Readonly<LazyInfo>; /** * The initializer function that will be called to construct the value. It will be cleared after * the value is constructed, unless `LAZY_NOCLEAR` is set. */ private _init; /** Has the initializer finished executing? */ get isReady(): boolean; [Symbol.iterator](): Iterator<any>; [Symbol.asyncIterator](): AsyncIterator<any>; private constructor(); static create<T>(f: () => T): Lazy<T>; private _makeDescription; /** Returns a short description of the Lazy value and its state. */ toString(): string; /** * Evaluates this {@link Lazy} instance, flattening any nested {@link Lazy} or {@link Promise} * types. * * @returns The value produced by the initializer, after flattening any nested {@link Lazy} or * {@link Promise} instances. * @throws The error thrown during initialization, if any. */ pull(): Pulled<T>; get [Symbol.toStringTag](): string; /** * Creates a new {@link Lazy} primitive that, when pulled, will pull **this** and return its * result, projected using the given function. If the Lazy primitive is async, the projection * will receive the awaited value. * * @example * // sync projectionL * const sync = lazy(() => "hello").map(x => `${x} world`) satisfies Lazy<string> * expect(sync.pull()).toBe("hello world") * * // sync projection on async lazy: * const async = lazy(async () => [1]).map(x => [...x, 2]) satisfies LazyAsync<number[]> * await expect(async.pull()).resolves.toBe(2) * * // async projection on sync lazy: * const nested = lazy(() => 1).map(async x => x + 1) satisfies LazyAsync<number> * await expect(nested.pull()).resolves.toBe(2) * * // async projection on async lazy: * const asyncToAsync = lazy(async () => 1).map( * async x => x + 1 * ) satisfies LazyAsync<number> * await expect(asyncToAsync.pull()).resolves.toBe(2) * * @param projection The function to apply to the value of the Lazy primitive. It will flatten * any nested {@link Lazy} and {@link Promise} instances. * @summary * Projects the result of this {@link Lazy} primitive using the given function. * @see {@link Array.map} for a similar method on arrays. * @see {@link Promise.then} for a similar method on promises. * @see {@link Lazy.do} for a similar method that doesn't change the result. */ map<S, R>(this: LazyAsync<S>, projection: (value: PulledAwaited<S>) => Promise<LazyAsync<R>>): LazyAsync<R>; map<S, Y>(this: LazyAsync<S>, projection: (value: PulledAwaited<S>) => Promise<LazyAsync<Y>>): LazyAsync<Y>; map<S, X>(this: LazyAsync<S>, projection: (value: PulledAwaited<S>) => Promise<Lazy<X>>): LazyAsync<X>; map<S, X>(this: LazyAsync<S>, projection: (value: PulledAwaited<S>) => Promise<X>): LazyAsync<X>; map<S, X>(this: LazyAsync<S>, projection: (value: PulledAwaited<S>) => LazyAsync<X>): LazyAsync<X>; map<S, R>(this: LazyAsync<S>, f: (value: PulledAwaited<S>) => Lazy<R>): LazyAsync<R>; map<S, R>(this: LazyAsync<S>, f: (value: PulledAwaited<S>) => R): LazyAsync<R>; map<Y>(projection: (value: PulledAwaited<T>) => Promise<LazyAsync<Y>>): LazyAsync<Y>; map<X>(projection: (value: PulledAwaited<T>) => Promise<Lazy<X>>): LazyAsync<X>; map<X>(projection: (value: PulledAwaited<T>) => Promise<X>): LazyAsync<X>; map<R>(projection: (value: PulledAwaited<T>) => Lazy<R>): Lazy<R>; map<R>(projection: (value: PulledAwaited<T>) => R): Lazy<R>; /** * Creates a new {@link Lazy} primitive that, when pulled, will pull **this** and apply the given * callback to the result. The new {@link Lazy} will still return the same value as **this**, * only waiting for the handler to finish first. * * @example * const lazy = lazy(() => 1).do(x => console.log(x)) satisfies Lazy<number> * expect(lazy.pull()).toBe(1) // Logs "1" to the console as a side effect. * const wait30 = lazy(() => 1).do( * async x => new Promise(r => setTimeout(r, 30)) * ) satisfies Lazy<number> * await expect(wait30.pull()).resolves.toBe(1) // Waits 30ms before returning 1. * * @param callback The callback * @summary Applies the given callback to the result of this {@link Lazy} primitive. */ do<S>(this: LazyAsync<S>, callback: (value: S) => any | Lazy<any> | Promise<any> | Promise<LazyAsync<any>> | LazyAsync<any>): LazyAsync<S>; do<T>(this: Lazy<T>, callback: (value: PulledAwaited<T>) => Promise<any> | LazyAsync<any>): LazyAsync<T>; do<T>(this: Lazy<T>, callback: (value: PulledAwaited<T>) => Lazy<any>): Lazy<T>; do<T>(this: Lazy<T>, callback: (value: PulledAwaited<T>) => any): Lazy<T>; /** * Zips **this** {@link Lazy} primitive with one or more others, returning a new {@link Lazy} * that, when pulled, will pull all of them and return an array with the results. If any * primitive involved is async, the new {@link Lazy} will also be async. * * @example * const a = lazy(() => 1).zip(lazy(() => 2)) satisfies Lazy<[number, number]> * expect(a.pull()).toEqual([1, 2]) * * const b = lazy(async () => 1).zip(lazy(() => 2)) satisfies LazyAsync<[number, number]> * await expect(b.pull()).resolves.toEqual([1, 2]) * * @param others One or more {@link Lazy} primitives to zip with **this**. * @summary Turns multiple lazy values into a single lazy value producing an array. */ zip<Others extends readonly [Pullable<unknown>, ...Pullable<unknown>[]]>(...others: Others): LazyAsync<any> extends [this, ...Others][number] ? LazyAsync<[ PulledAwaited<T>, ...{ [K in keyof Others]: PulledAwaited<Others[K]>; } ]> : Lazy<[ Pulled<T>, ...{ [K in keyof Others]: Pulled<Others[K]>; } ]>; /** * Takes an key-value object with {@link Lazy} values and returns a new {@link Lazy} that, when * pulled, will pull all of them and return an object with the same keys, but with the values * replaced by the pulled results. If any of the values are async, the new {@link Lazy} will also * be async. * * The value of **this** {@link Lazy} will be available under the key `"this"`. * * @example * const self = lazy(() => 1).assemble({ * a: lazy(() => 2), * b: lazy(() => 3) * }) * expect(self.pull()).toEqual({ this: 1, a: 2, b: 3 }) * * const asyncSelf = lazy(async () => 1).assemble({ * a: lazy(() => 2), * b: lazy(() => 3) * }) * await expect(asyncSelf.pull()).resolves.toEqual({ this: 1, a: 2, b: 3 }) * * @param assembly An object with {@link Lazy} values. * @returns A new {@link Lazy} primitive that will return an object with the same keys as the * input object, plus the key `"this"`, with the pulled results. * @summary Converts an object of {@link Lazy} values into a {@link Lazy} value producing an object. */ assemble<X extends Record<keyof X, Pullable<unknown>>>(assembly: X): LazyAsync<any> extends X[keyof X] | this ? LazyAsync<{ [K in keyof X]: PulledAwaited<X[K]>; } & { this: PulledAwaited<T>; }> : Lazy<{ [K in keyof X]: Pulled<X[K]>; } & { this: Pulled<T>; }>; } //# sourceMappingURL=lazy.d.ts.map