UNPKG

@thi.ng/rstream

Version:

Reactive streams & subscription primitives for constructing dataflow graphs / pipelines

165 lines 5.57 kB
import type { IObjectOf, Keys, NumOrString, Predicate2 } from "@thi.ng/api"; import type { CommonOpts, ISubscription } from "./api.js"; import { Subscription } from "./subscription.js"; export type KeyStreams<T, K extends Keys<T>> = { [id in K]-?: ISubscription<T[id], T[id]>; }; export interface StreamObjOpts<T, K extends Keys<T>> extends CommonOpts { /** * Array of selected `keys` (else selects all by default) for which to * create streams. */ keys: K[]; /** * If true (default), all created streams will be seeded with key values * from the source object. * * @defaultValue true */ initial: boolean; /** * Default values to use for `undefined` values of registered keys. */ defaults: Partial<T>; /** * If true, attaches * [`dedupe`](https://docs.thi.ng/umbrella/transducers/functions/dedupe.html) * transducer to each key's value stream to avoid obsolete downstream * propagation when a key's value hasn't actually changed. * * @defaultValue true */ dedupe: boolean; /** * Generic equality predicate to be used for `dedupe` (`===` by default). * Ignored if `dedupe` option is false. */ equiv: Predicate2<any>; } /** * Takes an arbitrary object `src` and object of options (see * {@link StreamObjOpts}). Creates a new object and for each selected key * creates a new subscription, optionally seeded with the key's value in `src`. * Returns new {@link StreamObj}. * * @remarks * The options arg is used to customize overall behavior of `fromObject` and * specify shared options for *all* created streams. * * A {@link StreamObj} is a full {@link Subscription}, in which additionally all * configured key streams are exposed under `streams`. The * {@link StreamObj.next} and {@link StreamObj.done} methods allow the * {@link StreamObj} itself to be used as subscriber for an upstream * subscribable (see 2nd example below): * * {@link StreamObj.next} receives an object of same type as `src` and feeds * each key's new value into its respective {@link StreamObj.streams}. If the * {@link StreamObjOpts.defaults} option is given, `undefined` key values are * replaced with their specified default. If {@link StreamObjOpts.dedupe} is * enabled (default) only changed values (as per {@link StreamObjOpts.equiv} * predicate option) will be propagated downstream. * * @example * ```ts tangle:../export/from-object.ts * import { fromObject, trace } from "@thi.ng/rstream"; * * type Foo = { a?: number; b: string; }; * * const obj = fromObject(<Foo>{ a: 1, b: "foo" }); * * obj.streams.a.subscribe(trace("a")); * // a 1 * * obj.streams.b.subscribe(trace("b")); * // b foo * * obj.next({ b: "bar" }); * // a undefined * // b bar * ``` * * @example * ```ts tangle:../export/from-object-2.ts * import { fromObject, subscription, trace } from "@thi.ng/rstream"; * * type Foo = { a?: number; b: string; }; * * const obj = fromObject(<Foo>{}, { keys: ["a", "b"], initial: false }); * obj.streams.a.subscribe(trace("a")); * obj.streams.b.subscribe(trace("b")); * * const src = subscription<Foo, Foo>(); * // use `obj` as subscriber itself * src.subscribe(obj); * * src.next({ a: 1, b: "foo" }); * // a 1 * // b foo * ``` * * @param src - * @param opts - */ export declare const fromObject: <T extends object, K extends Keys<T>>(src: T, opts?: Partial<StreamObjOpts<T, K>>) => StreamObj<T, K>; /** * Syntax sugar for {@link fromObject} for tuple/arrays. Returns a * {@link StreamObj} which provides individual subscriptions for each tuple * element, i.e. for 1:N fanout. * * @remarks * This construct is very useful for UI purposes, helping to provide both * finegrained and tuple-based reactive state for UI components used to edit * tuple/vector values (e.g. via individual per-tuple-element input * fields/controls). * * @example * ```ts tangle:../export/from-tuple.ts * import { fromTuple, subscription, trace } from "@thi.ng/rstream"; * * const tup = fromTuple([10, 20, 30]); * * tup.streams[0].subscribe(trace("[0]:")); * tup.streams[1].subscribe(trace("[1]:")); * tup.streams[2].subscribe(trace("[2]:")); * * // [0]: 10 * // [1]: 20 * // [2]: 30 * * tup.next([100,20,30]); * * // [0]: 100 * // (the two other streams didn't update since their values haven't changed) * ``` * * @param src * @param opts */ export declare const fromTuple: <T>(src: T[], opts?: Partial<StreamObjOpts<T[], number>>) => StreamObj<T[], number>; /** * See {@link fromObject} for details. */ export declare class StreamObj<T extends object, K extends Keys<T>> extends Subscription<T, T> { /** * Object of managed & typed streams for registered keys. */ keys: NumOrString[]; streams: IObjectOf<Subscription<any, any>>; defaults?: Partial<T>; constructor(src: T, opts?: Partial<StreamObjOpts<T, K>>); /** * Receives an object of configured type and feeds each key's new value into * its respective {@link StreamObj.streams}. If the * {@link StreamObjOpts.defaults} option is given, `undefined` key values * are replaced with their specified default. If * {@link StreamObjOpts.dedupe} is enabled (default) only changed values (as * per {@link StreamObjOpts.equiv} predicate option) will be propagated * downstream. * * @param x - */ next(x: T): void; done(): void; unsubscribe(sub?: ISubscription<T, any> | undefined): boolean; } //# sourceMappingURL=object.d.ts.map