UNPKG

jotai-eager

Version:

Jōtai utilities that help with asynchronous atoms

120 lines (112 loc) 6.01 kB
import { Atom, ExtractAtomValue, Getter, Setter, WritableAtom } from 'jotai/vanilla'; type AwaitAtomsValues<TTuple extends readonly [Atom<unknown>, ...Atom<unknown>[]]> = { [Index in keyof TTuple]: Awaited<ExtractAtomValue<TTuple[Index]>>; }; /** * Awaits all `deps` if necessary, then runs `op` given all deps in the same order. * If computing the value fails (throws), a rejected Promise is returned no matter if * the processing happened synchronously or not. * * @deprecated In favor of the eagerAtom() API. */ declare function derive<TDeps extends readonly [Atom<unknown>, ...Atom<unknown>[]], TValue>(deps: TDeps, op: (...depValues: AwaitAtomsValues<TDeps>) => TValue): Atom<TValue | Promise<Awaited<TValue>>>; type AwaitedAll<T extends readonly unknown[]> = { [K in keyof T]: Awaited<T[K] extends Atom<infer Value> ? Value : T[K]>; }; interface EagerGetter { /** * Retrieves the atom's fulfilled value. * If the value is not yet available, it interrupts the execution * of the eager atom until it's available. */ <Value>(atom: Atom<Value>): Awaited<Value>; /** * Retrieves the Promise's fulfilled value. * If the value is not yet available, it interrupts the execution * of the eager atom until it's available. */ await<T>(promiseOrValue: T): Awaited<T>; /** * Retrieves the fulfilled value of all passed in Promises. * If the values are not yet available, it interrupts the execution * of the eager atom until they're available. */ awaitAll<T extends readonly unknown[]>(args: T): AwaitedAll<T>; /** * Retrieves the fulfilled value of all passed in atoms. * If the values are not yet available, it interrupts the execution * of the eager atom until they're available. */ all<T extends readonly Atom<unknown>[]>(atoms: T): AwaitedAll<T>; } type Read<Value> = (get: EagerGetter) => Value; type Write<Args extends unknown[], Result> = (get: Getter, set: Setter, ...args: Args) => Result; type AsyncReadFunctionError = 'ERROR: The `read` function of eager atoms cannot be asynchronous, or return a Promise.'; /** * A drop-in replacement for vanilla atoms wih custom async read functions, that * removes unnecessary suspensions. The read function is written as if it was * synchronous, which allows for: * - eager computation of the atom's value in case all of its dependencies are fulfilled * (which is not the case for vanilla async atoms). * - interrupting computation if a dependency is not yet fulfilled. * * @param args A sync read function that can read async atoms directly using the `get` parameter. * @returns An eager atom */ declare function eagerAtom<Value, Args extends unknown[], Result>(...args: [Value] extends [PromiseLike<unknown>] ? [AsyncReadFunctionError] : [read: Read<Value>, write: Write<Args, Result>]): WritableAtom<Promise<Value> | Value, Args, Result>; declare function eagerAtom<Value>(...args: [Value] extends [PromiseLike<unknown>] ? [AsyncReadFunctionError] : [read: Read<Value>]): Atom<Promise<Value> | Value>; /** * Only useful if the eager atom's read function involves a try {} catch {}. Can be used to * detect whether a thrown value originates from `jotai-eager`, in which case should be rethrown. * @returns True if `error` is a suspension trigger originating from `jotai-eager`. */ declare function isEagerError(error: unknown): boolean; type Loadable<Value> = { state: 'loading'; } | { state: 'hasError'; error: unknown; } | { state: 'hasData'; data: Awaited<Value>; }; declare function loadable<Value>(anAtom: Atom<Value>): Atom<Loadable<Value>>; /** * Executes `process` with `data` as input synchronously if `data` is known, meaning * it is not an unresolved promise of the value. * * @param data The data to process, now or later (soon) * @param process The processing function * @returns The result (or promise of result) from running `process`. */ declare function soon<TInput, TOutput>(data: TInput, process: (knownData: Awaited<TInput>) => TOutput): TOutput | Promise<Awaited<TOutput>>; /** * Executes `process` with `data` as input synchronously if `data` is known, meaning * it is not an unresolved promise of the value. * * @param process The processing function * @returns A function that can be called with `data`, and returns the * result (or promise of result) from running `process` on `data`. */ declare function soon<TInput, TOutput>(process: (knownData: NoInfer<Awaited<TInput>>) => TOutput): (data: TInput) => TOutput | Promise<Awaited<TOutput>>; type PromiseOrValue<T> = Promise<T> | T; type SoonAll<T extends readonly unknown[]> = PromiseOrValue<{ [Index in keyof T]: Awaited<T[Index]>; }>; /** * Given array `values`, if all elements are known (are not unresolved promises), * returns an array of the same length with Awaited `values`. Otherwise, it returns a * promise to that array. */ declare function soonAll<T extends readonly unknown[] | []>(values: T): SoonAll<T>; declare function soonAll<T extends readonly unknown[]>(values: T): SoonAll<T>; interface WithPendingContext<Value> { get: Getter; prev: Awaited<Value> | undefined; pending: PromiseLike<Awaited<Value>>; } declare function withPending<Value, Args extends unknown[], Result>(anAtom: WritableAtom<Value, Args, Result>): WritableAtom<Awaited<Value> | undefined, Args, Result>; declare function withPending<Value, Args extends unknown[], Result, PendingValue>(anAtom: WritableAtom<Value, Args, Result>, fallback: (ctx: WithPendingContext<Value>) => PendingValue): WritableAtom<Awaited<Value> | PendingValue, Args, Result>; declare function withPending<Value>(anAtom: Atom<Value>): Atom<Awaited<Value> | undefined>; declare function withPending<Value, PendingValue>(anAtom: Atom<Value>, fallback: (ctx: WithPendingContext<Value>) => PendingValue): Atom<Awaited<Value> | PendingValue>; export { derive, eagerAtom, isEagerError, loadable, soon, soonAll, withPending };