StringUnionProperty
StringUnionProperty<T extends string> (from scenerystack/axon) is a thin Property subclass for the common TypeScript idiom of using a string literal union ('small' | 'medium' | 'large') as a lightweight enumeration, instead of an EnumerationProperty backed by a Rich Enumeration class. It requires validValues at construction (there's no way to construct one without it) and derives the PhET-iO phetioValueType from that list automatically via StringUnionIO.
import { StringUnionProperty } from 'scenerystack/axon';
type SizeChoice = 'small' | 'medium' | 'large';
const sizeProperty = new StringUnionProperty<SizeChoice>( 'medium', {
validValues: [ 'small', 'medium', 'large' ]
} );
sizeProperty.value = 'large'; // fine
// sizeProperty.value = 'huge'; // would throw an assertion error — not in validValuesConstructor
new StringUnionProperty<T extends string>( value: T, providedOptions: StringEnumerationPropertyOptions<T> )Unlike plain Property, the options argument is required — validValues has no default and must be supplied.
Options
StringUnionProperty accepts the same PropertyOptions<T> as Property, with two differences:
| Option | Effect |
|---|---|
validValues | Required. The full list of legal string literal values — also used to build the phetioValueType |
phetioValueType | Not settable — StringUnionProperty always computes it from validValues via StringUnionIO |
Everything else (tandem, units, reentrant, …) works exactly as it does on Property.
When to reach for this instead of EnumerationProperty
Use StringUnionProperty when the set of choices is small, has no associated behavior/data beyond the label itself, and is naturally expressed as a TypeScript string literal union already used elsewhere in your model's types. Use EnumerationProperty instead when the values need to carry additional data or methods (a full PhET "Rich Enumeration" class) — see the Enumeration Pattern for the tradeoffs between the two approaches.