- type ObjectKey: number | string | symbol
No description.
- type FilterFunction: (obj: object, path: ObjectKey[]) => boolean
No description.
Central configuration for registering properties.
If given an array, properties will be registered separately for each configuration, each pointing to the next by linking their endpoints and targets. This results in multiple intermediate sequential data storages, propagated from last to first.
Example
const storage = new ReactiveStorage([ { getter: ({ val }) => Math.round(val / 50) * 50 }, { getter: ({ val }) => Math.round(val / 5) * 5 }, ]); storage.registerRecursive('value', 62);
console.log(storage.targets[1].value) // 60 // Second getter turns 62 into 60 console.log(storage.targets[0].value) // 50 // Second getter turns 62 into 60
See also
OptionsWhole
- type
Options<KV
extends
Record<ObjectKey, any>>: {[Prop in keyof OptionsWhole<KV>]: Prop extends "depth"}? number | Options<KV> : OptionsWhole<KV>[Prop]?
No description.
class ReactiveStorage<KV extends Record<ObjectKey, any>>
- ReactiveStorage<KV extends Record<ObjectKey, any>>(config: Configuration<KV> = {}): ReactiveStorage<KV>
No description.
The endpoint holding the actual data of the registered properties.
See also
OptionsWhole.endpoint
The first access point for registered properties. Always the first element of
targets
.See also
OptionsWhole.target
All access points for registered properties in sequential order. This is only relevant if having defined multiple configurations, and such, multiple intermediate storage points. Otherwise
target
can be used as well.See also
OptionsWhole.targets
- readonly config: OptionsWhole<KV>[]
No description.
- static
readonly
Filter: {objectLiteralOrArray: (obj: object) => boolean,}
any: () => true See also
Filter
- register<K extends string | number | symbol>(): ReactiveStorage<KV>
Register one or multiple reactive properties according to the current instance's configuration (
config
) and the given initial value, if any.Parameters
-
key
: The property name to register ontarget
. -
initialValue
: The initial value that will be assigned after registering.
Returns The current
ReactiveStorage
instance for easy chaining.-
- registerFrom(object: Partial<KV>): ReactiveStorage<KV>
Register all property keys and symbols of the given object with their respective values according to the current instance's configuration (
config
).Parameters
-
object
: The object the keys and symbols of will be registered.
Returns The current
ReactiveStorage
instance for easy chaining.-
- static register<>(key: K | K[],): RegistrationData<KV>
initialValue?: V,
config: Configuration<KV> = {} Register a reactive property one or multiple targets that point to an endpoint. If left unspecified, target and/or endpoint will be a new object that can be obtained using the returned data.
Parameters
-
key
: The property name to register. -
initialValue
: The initial value that will be assigned after registering.
-
- static registerFrom<KV extends Record<ObjectKey, any>>(object: KV,): RegistrationData<KV>
config: Configuration<KV> Register all property keys and symbols of the given object with their respective values. If left unspecified, target and/or endpoint will be a new object that can be obtained using the returned data.
Parameters
-
object
: The object the keys and symbols of will be registered.
-
- static registerRecursive<>(key: K | K[],): RegistrationData<KV>
initialValue?: V,
config: Configuration<KV> = {} Same as
register
but register properties infinitely deep. Values (both the initial value and values assigned at a later point in time) will be recursively traversed and registered, limited byOptions.deepFilter
.Shorthand for
register
with the the deepest configuredOptions.depth
set toInfinity
.Parameters
-
key
: The property name to register. -
initialValue
: The initial value that will be assigned after registering.
-
- static registerRecursiveFrom<>(object: KV,): RegistrationData<KV>
config: Configuration<KV> Same as
registerFrom
but register all properties within the given object infinitely deep. Values (both the initial values and values assigned at a later point in time) will be recursively traversed and registered, limited byOptions.deepFilter
.Parameters
-
object
: The object the keys and symbols of will be registered.
-
interface RegistrationData<KV extends Record<ObjectKey, any>>
The endpoint holding the actual data of the registered properties.
See also
OptionsWhole.endpoint
The first access point for registered properties. Always the first element of
targets
.See also
OptionsWhole.target
All access points for registered properties in sequential order. This is only relevant if having defined multiple configurations, and such, multiple intermediate storage points. Otherwise
target
can be used as well.See also
OptionsWhole.targets
interface GetterEvent
Options.getter
event argument.
- val: any
Value that was fetched, from the underlying endpoint.
Key path of the property in question, starting with the registered key.
Example
const storage = new ReactiveStorage({ getter: ({ path }) => { console.log("GET:", path) }, }); storage.registerRecursive('value', { first: { second: 3 } });
// <Logs from the initial assignment...>
storage.data.value.first.second; // "GET: ['value']" // "GET: ['value', 'first']" // "GET: ['value', 'first', 'second']"
interface SetterEvent implements PostSetterEvent
Options.setter
event argument.
- initial: boolean
Whether this call is propagated by the initial registration action.
- prevVal: any
Previous value.
Key path of the property in question, starting with the registered key.
Example
const storage = new ReactiveStorage({ setter: ({ path }) => { console.log("SET:", path) } }); storage.registerRecursive('value', { first: { second: 3 } });
// <Logs from the initial assignment...>
storage.data.value.first.second = 4 // "SET: ['value', 'first', 'second']"
- val: any
Value to be set.
- set: (val: any) => void
Default setter that can be used to set a value different from the passed one to the expected endpoint. When using it, you should prevent the default value from being set by returning
true
.
interface PostSetterEvent
Options.postSetter
event argument.
- val: any
Value that was set.
- initial: boolean
Whether this call is propagated by the initial registration action.
- prevVal: any
Previous value.
Key path of the property in question, starting with the registered key.
Example
const storage = new ReactiveStorage({ setter: ({ path }) => { console.log("SET:", path) } }); storage.registerRecursive('value', { first: { second: 3 } });
// <Logs from the initial assignment...>
storage.data.value.first.second = 4 // "SET: ['value', 'first', 'second']"
interface OptionsWhole<KV extends Record<ObjectKey, any>>
The endpoint that the registered property points to which holds the actual data, so an object that the configured setter and getter will deposit the value to and fetch the value from, respectively.
Default
{}
An object that represents the access point for the registered properties. Values are deposited at the specified
endpoint
.Default
{}
Decide whether to deeply register an object covered by
depth
. This is useful to mitigate registering properties within any object (class instances, DOM nodes, etc.) in favor of simpler objects – especially when making use of an infinite depth.Be careful when changing this, especially when there is user input involved! Unrestricted recursion may lead to a significant overload or even an infinite loop when (accidentally) assigning huge objects like a DOM node.
Just like all other configuration options, this will be passed down into any depth unless overridden.
Remarks
Filter
provides some useful filter functions.Example
The first layer will deeply register any object, depth 1 and below accept only object literals or arrays.
ReactiveStorage.registerRecursive('value', 420, { setter: val => { console.log("SET", val) }, depthFilter: Filter.any, depth: { depthFilter: Filter.objectLiteralOrArray } });
Default
- enumerable?: boolean
Whether registered properties should be enumerable inside
target
. Corresponds toPropertyDescriptor.enumerable
.Default
true
- depth?: number | Omit<OptionsWhole<Record<ObjectKey, any>>, "target">
Whether and how keys inside any object or array value should be registered such that they go through additional layers of getters and setters. If a value is reassigned, it is re-registered with the same configuration until the given depth. The immediate registered value is depth 0.
If given registration options, the registered key configuration will assume these options in their layer. Can be nested infinitely deep.
If given a number, keys will be registered recursively up until the given depth, assuming the options present in the given scope. Can be
Infinity
.Example (Different options from layer 2 onwards)
const storage = new ReactiveStorage({ setter: val => { console.log("First layer:", val) }, depth: { setter: val => { console.log("Further layer:", val) }, depth: Infinity } }); storage.register('recursive', { first: { second: 3 } });
// <Logs from the initial assignment...>
storage.data.recursive = { first2: { second2: 69 } }; // "First layer: { first2: { second2: 69 } }" // "Further layer: { second2: 69 }" // "Further layer: 69"
storage.data.recursive.first2 = 70; // "Further layer: 70"
Example (Re-register a deep value)
Even though the initial hierarchy is temporarily deleted by assigning a primitive value of "4", another reassigned value is simply re-registered with the initial configuration (note that since the
depth
is merely set to 1, any potential value insidesecond2
will not be reactive).const storage = new ReactiveStorage({ setter: val => { console.log("SET", val) }, depth: 1 }); storage.register('value', { first: { second: 3 } });
// "SET { first: { second: 3 } }" // "SET { second: 3 }"
storage.data.value = 4 // "SET 4"
storage.data.value = { first2: { second2: { third2: 'foobar' } } } // "SET { first2: { second2: { third2: 'foobar' } } }" // "SET second2: { third2: 'foobar' } }"
Default
0
- postSetter?: (event: PostSetterEvent) => void
Called after a value has been set.
- setter?: (event: SetterEvent) => boolean | void
Called before a value is set.
Return
true
to prevent the value from being set to the default endpoint. This can be useful to filter specific values or when setting them manually, in which case the passedSetterEvent.set
is useful.- getter?: (event: GetterEvent) => any
Called anytime a value is fetched.
Remarks
This is potentially called a lot since, as per the getter/setter hierarchy, any deep value set needs to get the respective value from a layer above.
Example
const storage = new ReactiveStorage({ getter: val => { console.log("GET", val) }, depth: Infinity }); storage.register('value', { first: { second: 3 } });
storage.data.value.first.second = 8 // "GET { first: { second: 3 } }" // "GET { second: 8 }" // "GET 8"
variable Filter
Provides some useful filter functions for use in
Options.depthFilter
.
Also exposed via ReactiveStorage.Filter
.