All files / src combine.ts

100% Statements 3/3
100% Branches 2/2
100% Functions 2/2
100% Lines 3/3

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61                                                                                                      18x     10x     23x      
import { compute } from "./compute";
import { type Config, type OwnedReadable, type ReadableLike } from "./interface";
 
export type MapReadablesToValues<TDepValues extends readonly ReadableLike[]> = {
  [K in keyof TDepValues]: TDepValues[K] extends ReadableLike<infer V> ? V : never;
};
 
export interface Combine {
  /**
   * Combines an array of {@link ReadableLike}s into a single {@link Readable} with the array of values.
   * @param deps An array of {@link ReadableLike}s to combine.
   * @returns A {@link Readable} with the combined values.
   */
  <TDeps extends readonly ReadableLike[] = ReadableLike[]>(deps: TDeps): OwnedReadable<MapReadablesToValues<TDeps>>;
  /**
   * Combines an array of {@link ReadableLike}s into a single {@link Readable} with transformed value.
   * @param deps - An array of {@link ReadableLike}s to combine.
   * @param transform - A pure function that takes multiple values and returns a new value.
   * @param config - Optional custom {@link Config}.
   * @returns A {@link Readable} with the transformed values.
   */
  <TDeps extends readonly ReadableLike[] = ReadableLike[], TValue = any>(
    deps: TDeps,
    transform: (...deps: MapReadablesToValues<TDeps>) => TValue,
    config?: Config<TValue>,
  ): OwnedReadable<TValue>;
}
 
/**
 * Combine an array of {@link ReadableLike}s into a single {@link Readable} with transformed value.
 *
 * Unlike {@link compute}, the signature of the `transform` function is pure,
 * which makes it easier to use functions that are not aware of the reactive system.
 *
 * @function
 * @category Derivations
 * @param deps - An array of {@link ReadableLike}s to combine.
 * @param transform - Optional pure function that takes multiple values and returns a new value.
 * @param config - Optional custom {@link Config}.
 * @returns A {@link OwnedReadable} with transformed value.
 *
 * @example
 * ```ts
 * import { combine, writable } from "@embra/reactivity";
 *
 * const v1$ = writable(0);
 * const v2$ = writable(0);
 *
 * const combined$ = combine([v1$, v2$], (v1, v2) => v1 + v2);
 * ```
 */
export const combine: Combine = <TDeps extends readonly ReadableLike[], TValue = any>(
  deps: TDeps,
  transform?: (...deps: MapReadablesToValues<TDeps>) => TValue,
  config?: Config<TValue>,
) =>
  compute(
    get => (transform ? transform(...(deps.map(get) as MapReadablesToValues<TDeps>)) : (deps.map(get) as TValue)),
    config,
  );