Types

ReactiveJS provides Structured Records (a set of fields which are all present in a value) and Tagged Unions (a set of fields where just one is present at any one time), both supporting Generic Types.

Reactive.Module("People", () => {
  Reactive.Struct("Person", () => {
    Reactive.Field(Text.Plain, "name");
    Reactive.Field(Maths.Integer.Number, "age");
  });

  Reactive.Union("Contact", () => {
    Reactive.Field(Text.Plain, "email");
    Reactive.Field(Text.Plain, "phone");
  });
});
Defining a struct type and a union type in a module

Struct types

A struct type contains a set of fields which are all present in any instance of this type.

Definition

Give the struct a Reactive.Field for each field. Field takes the type, then the name. A field is ordinary data.

Reactive.Struct("Person", () => {
  Reactive.Field(Text.Plain, "name");
  Reactive.Field(Maths.Integer.Number, "age");
});
Person has a name and an age. Each field is the type, then the name.

Creation

The callback's parameters are the generic types. A callback with no parameters is the constructor. Call it with the field values in the order the fields were declared. A callback with parameters takes those types and returns the constructor.

const ada = People.Person("Ada Lovelace", 36);
Creating a Person struct. The callback took no type arguments, so Person is the constructor.

Field Values

Reach a field with plain dotted access. ada.name is the reactive value for that field.

Content.Text(ada.name);
Reading a field.

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

An option is the same Reactive.Field line. Option names are lowercase. A locked payload does not lock the union value. Reading the option does.

Reactive.Union("Contact", () => {
  Reactive.Field(Text.Plain, "email");
  Reactive.Field(Text.Plain, "phone");
});
Contact has an email option and a phone option.

Creation

Construct a union by calling the variant: MyModule.UnionName.variantName(...). That call selects the variant. The callback's parameters are the generic types. A callback with no parameters puts those variant constructors on the union. A callback with parameters takes those types and returns the union whose variants are the constructors.

const how = People.Contact.email("ada@engine.org");
People.Contact.email builds the email variant.

Variant Values

how.email is an optional of that option's type. It is present when the union is that option. Collection.Optional is a context. some carries the value. none carries Collection.Void. Collection.Optional.Default returns the value, or the fallback when the optional is none.

const address = Collection.Optional.Default(how.email, "");
Content.Text(address);
Read one option. The result is an optional, then the value or the fallback.

Generic types

A generic type takes one or more types and uses those types in its fields. One definition then builds a struct or a union for each set of types you pass.

Defining generic types

The parameters of the callback are the generic types. A field uses a parameter as its type. A struct lists every field. A union lists its options, and a value has one of them.

Reactive.Module("People", () => {
  // a record: both fields are present, each of its own type
  Reactive.Struct("Pair", (Left, Right) => {
    Reactive.Field(Left, "left");
    Reactive.Field(Right, "right");
  });

  // a union: one option is present, and ok carries the given type
  Reactive.Union("Result", (Value) => {
    Reactive.Field(Value, "ok");
    Reactive.Field(Text.Plain, "error");
  });
});
Pair takes two types. Result takes one type.

Using them

Call the name with the types. A struct call returns the constructor, and that constructor takes the field values in order. A union call returns the variants, and a variant call builds the value.

// create a Pair of a string and an integer
const NameAndAge = People.Pair(Text.Plain, Maths.Integer.Number);
const ada = NameAndAge("Ada Lovelace", 36);

// create a Result of a string
const TextResult = People.Result(Text.Plain);
const saved = TextResult.ok("saved");
Pass the types, then build the value.

Built-in types

String, integer, and float come from the driver that implements their context. The integer type is Maths.Integer.Number. Logic.Maybe is the boolean, and If reads it. An array is Collection.Array.Of(ElementType). Examples write strings as Text.Plain and floats as Maths.Real.

Reactive.Type("Name", Other) names an alias of Other. An alias is a different type from the type it names. A place that expects a type accepts an alias of that type. A sibling alias is not accepted.