shelving
Version:
Toolkit for using data in JavaScript.
59 lines (58 loc) • 2.09 kB
TypeScript
import { type ImmutableArray } from "./array.js";
import type { BranchData, BranchKey, Data, LeafData, LeafKey } from "./data.js";
/**
* Set of named updates for a data object.
*
* Note: string templates infer best when you have fixed character(s) at the start,
* so our `Update` syntax always
*/
export type Updates<T extends Data = Data> = {
/**
* Set update (all branches)
* - Can set `a` and `a.a1` in `{ a: { a1: 123 } }`
* - Sometimes inference gets confused, if that happens use `=` syntax instead.
*/
readonly [K in BranchKey<T> as `${K}`]?: BranchData<T>[K] | undefined;
} & {
/**
* Set update (leaves only)
* - Can set `a.a1` in `{ a: { a1: 123 } }`, but cannot set `a`
* - Deeply-nested properties don't always infer when leaves and branches are combined.
* - This syntax is more exact and will infer better.
*/
readonly [K in LeafKey<T> as `=${K}`]?: LeafData<T>[K] | undefined;
} & {
/**
* Sum update.
* - Increment/decrement numbers.
*/
readonly [K in LeafKey<T> as `+=${K}` | `-=${K}`]?: LeafData<T>[K] extends number ? LeafData<T>[K] | undefined : never;
} & {
/**
* With/omit update.
* - Add or remove items from arrays.
*/
readonly [K in LeafKey<T> as `+[]${K}` | `-[]${K}`]?: LeafData<T>[K] extends ImmutableArray<unknown> ? LeafData<T>[K] | LeafData<T>[K][number] | undefined : never;
};
/** A single update to a keyed property in an object. */
export type Update = {
action: "set";
key: string;
value: unknown;
} | {
action: "with";
key: string;
value: ImmutableArray<unknown>;
} | {
action: "omit";
key: string;
value: ImmutableArray<unknown>;
} | {
action: "sum";
key: string;
value: number;
};
/** Yield the prop updates in an `Updates` object as a set of `Update` objects. */
export declare function getUpdates<T extends Data>(data: Updates<T>): ImmutableArray<Update>;
/** Update a data object with a set of updates. */
export declare function updateData<T extends Data>(data: T, updates: Updates<T>): T;