Skip to content

DerivedProperty ​

DerivedProperty<T, ...> (from scenerystack/axon) is a read-only Property whose value is automatically recomputed whenever any of its dependency Properties change. It extends the same ReadOnlyProperty base as Property, so it supports .value, .link(), .lazyLink(), etc. — but calling .value = ... on it is a programming error; the value can only change via the derivation function.

ts
import { DerivedProperty, NumberProperty } from 'scenerystack/axon';

const widthProperty = new NumberProperty( 4 );
const heightProperty = new NumberProperty( 3 );

const areaProperty = new DerivedProperty(
  [ widthProperty, heightProperty ],
  ( width, height ) => width * height
);

areaProperty.link( area => console.log( 'area:', area ) ); // logs "area: 12" immediately
widthProperty.value = 5;                                    // logs "area: 15"

The derivation function receives the current .value of each dependency, in the same order as the dependencies array, and its return type determines T.

Constructor ​

ts
new DerivedProperty( dependencies, derivation, providedOptions? )

dependencies is an array of up to 15 TReadOnlyProperty<...> instances (any Property, including another DerivedProperty); overloads pick the matching arity so derivation's parameter types line up automatically.

Members ​

MemberEffect
recomputeDerivation()Force a recompute — useful when a non-Property event (an Emitter, an observable array's elementAddedEmitter) should also trigger recomputation
hasDependency( dependency )Whether a given Property is one of this DerivedProperty's dependencies
dispose()Unlinks from every dependency; always dispose a DerivedProperty you own once it's no longer needed

Static factories ​

Rather than writing a derivation by hand for common cases, DerivedProperty offers static helpers that return a TReadOnlyProperty:

Static methodProduces
DerivedProperty.and( properties )true iff every boolean-valued Property is true
DerivedProperty.or( properties )true iff any boolean-valued Property is true
DerivedProperty.not( property )The logical inverse of a boolean Property
DerivedProperty.valueEquals( a, b )true iff a.value === b.value
DerivedProperty.valueNotEquals( a, b )true iff a.value !== b.value
DerivedProperty.valueEqualsConstant( a, value )true iff a.value === value
DerivedProperty.add( properties ) / .multiply( properties )Sum / product of number-valued Properties
DerivedProperty.toFixedProperty( numberProperty, decimalPlaces )A string Property formatting the number to a fixed number of decimals
DerivedProperty.fromRecord( key, record )Looks up record[key.value], following through if the record's value is itself a Property
DerivedProperty.deriveAny( dependencies, derivation )Escape hatch for more than 15 dependencies or a dynamically-sized dependency array
ts
import { BooleanProperty } from 'scenerystack/axon';

const isRunningProperty = new BooleanProperty( true );
const isEnabledProperty = new BooleanProperty( true );

const isActiveProperty = DerivedProperty.and( [ isRunningProperty, isEnabledProperty ] );

Read-only — and remember to dispose

DerivedProperty overrides set/value= to throw; it's read-only by design (phetioReadOnly: true internally). It also lazyLinks to every dependency in its constructor, so an undisposed DerivedProperty keeps its dependencies alive — always call .dispose() when the derived value is no longer needed, symmetric with any Property you construct yourself.

If you need to react to several Properties without producing a new Property value — just running a side-effecting callback — use Multilink instead.