entangled
Creates an object whose ref properties are automatically unwrapped by default.
Usage
import { entangled, markDescriptor } from '@8ctavio/vergil'
// Define regular or ref properties
const _entangled = entangled({
prop1: 1,
prop2: ref(2)
})
// Ref properties are unwrapped by default
console.log(_entangled.prop1) // 1
console.log(_entangled.prop2) // 2
// Extend entangled and configure properties
_entangled.extend({
prop3: 3,
prop4: markDescriptor({
value: 4,
enumerable: false,
writable: false
}),
prop5: markDescriptor({
value: ref(5),
unwrap: false
})
})
Description
The entangled
function creates and returns an entangled object.
Entangled objects inherit an extend
method from their prototype, which is internally called and forwarded entangled
's parameters — properties
and options
— to define properties of newly created entangled objects.
entangled(properties, options)
// same as
entangled().extend(properties, options)
Property definition
Entangled objects' extend
method allows to further define properties on entangled objects. The extend
method returns the entangled object it is called on, and accepts two parameters: extension
and options
.
The extension
parameter is an object whose own key-value pairs represent the key and descriptor pairs used to define corresponding properties on the entangled object with Object.defineProperty
.
An entangled object property descriptor may be directly provided through an extension
property value as a descriptor-marked object returned by the markDescriptor
function. However, for convenience, any other provided property value x
is inferred as a data descriptor of the form { value: x }
.
entangled().extend({
foo: markDescriptor({ /* ... */ }),
bar: baz // equivalent to markDescriptor({ value: baz })
})
The options
parameter is an object whose properties configure the property definition process. The options.ignore
option, for instance, accepts an array of extension
property keys not to be defined on the underlying entangled object.
Other options
properties define the default property values of entangled object descriptors.
Default descriptor options
By default, entangled object properties created with the extend
method are configurable, enumerable, and writable (if applicable).
// configurable, enumerable, and writable
entangled({ /* ... */ })
The default configurability, enumerability, and writability of entangled object properties created with .extend
may be individually configured through corresponding options.configurable
, options.enumerable
, and options.writable
boolean options.
// configurable, non-enumerable, and non-writable
entangled({ /* ... */ }, { enumerable: false, writable: false })
The default value for the configurable
, enumerable
, and writable
options is obtained from the options.defaults
property, which itself defaults to true
. Thus, if options.defaults
is set to false
, properties created with extend
are non-configurable, non-enumerable, and non-writable (if applicable), unless some of the descriptor-property-specific options are overwritten.
// non-configurable, enumerable, and non-writable
entangled({ /* ... */ }, { defaults: false, enumerable: true })
Ref unwrapping
Entangled objects' ref properties defined with the extend
method are automatically unwrapped by default. This is achieved by defining the ref property with an accessor descriptor. Therefore, ref property descriptors may also include custom get
and set
methods to overwrite default behavior.
const _entangled = entangled({
foo: ref(0),
bar: markDescriptor({
value: ref(),
get: () => {
console.log('custom getter')
},
set: (value) => {
console.log('custom setter')
}
})
})
watchSyncEffect(() => {
console.log(_entangled.foo)
})
_entangled.foo++
_entangled.bar = _entangled.bar
// Logs:
// 0
// 1
// custom getter
// custom setter
Nevertheless, non-unwrapped refs can be defined on entangled objects by providing the refs through descriptor-marked objects with an unwrap
property set to false
.
const _entangled = entangled({
foo: markDescriptor({
value: ref(),
unwrap: false
})
})
console.log(isRef(_entangled.foo)) // true
In addition, entangled objects inherit a getRef
method from their prototype to retrieve the underlying ref object of auto-unwrapped ref properties. The getRef
method accepts a single key
argument, an auto-unwrapped ref property key. If the entangled object's key
property is not an auto-unwrapped ref, getRef
returns undefined
.
const _entangled = entangled({
foo: ref()
})
console.log(isRef(_entangled.getRef('foo'))) // true
console.log(_entangled.getRef('bar')) // undefined
Finally, in order to support the getRef
method, custom getters of auto-unwrapped ref properties receive a shouldUnwrap
boolean argument. When shouldUnwrap
is false
, a custom getter should return a ref object; if something else is returned, getRef
returns undefined
for that custom getter's property key.
entangled({
foo: markDescriptor({
value: ref(),
get(shouldUnwrap) {
if (!shouldUnwrap) {
// should return a ref
return /* ... */
}
}
})
})
Definition
function entangled<T extends Record<PropertyKey, unknown> = {}>(
properties?: T,
options?: EntangledOptions
): Entangled<T>
interface EntangledOptions {
defaults?: boolean;
configurable?: boolean;
enumerable?: boolean;
writable?: boolean;
ignore?: PropertyKey[];
}
type Entangled<E extends Record<PropertyKey, unknown>> = EntangledExtension<E> & {
getRef(key: PropertyKey): Ref | undefined
extend(extension: Record<PropertyKey, unknown>, options?: EntangledOptions): object
}
Parameters
properties
: Object whose own key-value pairs represent key-descriptor pairs used to define corresponding properties on the underlying entangled object. See property definitionoptions
:defaults
: Default value of theconfigurable
,enumerable
, andwritable
options. Defaults totrue
.configurable
: Defaultconfigurable
property value for descriptors of newly created properties. Defaults todefaults
.enumerable
: Defaultenumerable
property value for descriptors of newly created properties. Defaults todefaults
.writable
: Defaultwritable
property value for descriptors of newly created properties. Defaults todefaults
.ignore
: Array ofproperties
property keys not to be defined on the underlying entangled object.
Return value
An entangled object.