Documentation
Schema
Either states

Either states

In the previous section, we learned about state inheritance and how it allows us to define a hierarchy of related states. However, sometimes it's useful to define states that are not related in a hierarchical way. This is where the either keyword comes in.

The either keyword allows us to define an either state, which is a union of two or more states that are not related in a hierarchical way. An either state can be used to represent multiple states that share some common properties or behaviors, but cannot be expressed using inheritance.

Syntax

The syntax for an either state is as follows:

either User = RegisteredUser | ActiveUser

In this example, we define an either state called User that can be either a "RegisteredUser" or an "ActiveUser". The | symbol is used to separate the different states that make up the either state.

Motivation and use cases

Relationship between states

One use case for an either state is to define a relation between entities. For example, if we have an entity called "Order" and we want to associate it with a "User", we can define the "User" state as an either state that includes both "RegisteredUser" and "ActiveUser" states. Then, we can define a field on the "Order" entity that references a "User", and the field can be of type "User".

state Order {
  user: User = 1
}

Common properties and mutations

Another use case for an either state is to define mutations that apply to multiple states. For example, if we want to define a mutation that allows a user to update their personal information, we can define the mutation on top of "User" directly. This will allow the mutation to be used with both "RegisteredUser" and "ActiveUser" states without having to define the mutation twice.

User.updatePersonalInfo(
  firstName: String,
  lastName: String,
): User

Please note that you can only use an either state as a return type for a mutation if the same either state is used as the input type for the mutation. For example, the following mutation is not valid because the input type is "RegisteredUser" and the return type is "User".

RegisteredUser.updatePersonalInfo(
  firstName: String,
  lastName: String,
): User

However, the opposite is valid because the input type is "User" and the return type is "RegisteredUser".

User.updatePersonalInfo(
  firstName: String,
  lastName: String,
): RegisteredUser

In the upcoming section, we'll explore how to use mutations in more detail.