Types

Types define the shape of your data. These can either be records, made with the Reactive.Field command, or tagged unions, made with the Reactive.Variant command.

Reactive.Module("People", () => {
  Reactive.Type("Person", () => {        // a record — has Fields
    Reactive.Field("name", Text);
    Reactive.Field("age",  Maths.Real);
  });

  Reactive.Union("Contact", () => {       // a union — has Variants
    Reactive.Variant("email", Text);
    Reactive.Variant("phone", Text);
  });
});
Defining a record type and a union type in a module

Record types

Record types contain a set of fields which are all present in any instance of this type.

Definition

Declare a Reactive.Type and give its body a Reactive.Field for each named part, along with the type of that part.

Reactive.Type("Person", () => {
  Reactive.Field("name", Text);
  Reactive.Field("age",  Maths.Real);
});
Defining a Person record with two fields

Creation

The type is its own constructor. Call it with one positional argument per field, in the order they were declared, to make an instance.

const ada = People.Person("Ada Lovelace", 36);
Creating a Person record instance

Using

Reach a field with plain dotted access. ada.name is the reactive value for that field, the same expression you read from.

Content.Text(ada.name);   // read the field
Reading a field with dotted access

Writing

If a field is part of an object held as state, it can also be updated by any function that can update its input. The field carries its own writable half, so passing it to an input writes straight back into the state.

const ada = Reactive.State(People.Person)(People.Person("Ada Lovelace", 36));

Input.Text(ada.name);   // edit the field — writes back into the state
Editing a field bound to state

Reversibility

Because the field is settable, you can also drive it from a reverse: set the field inside a reverse command and a write to the derived value flows straight back into it.

const naming = Reactive.Reverse((name) => {
  Reactive.Set(ada.name, name);   // the write flows back into the field
});
Driving a field from a reverse

Tagged union types

Tagged union types hold exactly one of a set of named variants at a time. The tag says which variant is in play, and each variant carries a value of its own type.

Definition

Give the Reactive.Union body a Reactive.Variant for each variant. Variant names are lowercase.

Reactive.Union("Contact", () => {
  Reactive.Variant("email", Text);
  Reactive.Variant("phone", Text);
});
Defining a Contact union with two variants

Creation

Call the variant by name to make a value tagged as that variant, passing the variant's value.

const how = People.Contact.email("ada@engine.org");
Creating a union value tagged as a variant

Using

Reaching a variant yields an optional that is present only when the value is currently that variant, so you match by running a block on the variant you care about; the unwrapped value arrives as an argument.

Collection.Optional.If(how.email, () => {
  const address = Reactive.Argument();   // the Text, present only when tagged email
  Content.Text(address);
});
Matching on a union option to unwrap its value

Built-in types

The scalar leaves ship with the framework and can be used as field, option and argument types anywhere. Each has a page in the module reference: