Docs / Language Manual / Extensible Variant
Edit

You are currently looking at the v11.0 docs, which are still a work in progress. If you miss anything, you may find it in the older v10.0 docs here.

Extensible Variant

Variant types are usually constrained to a fixed set of constructors. There may be very rare cases where you still want to be able to add constructors to a variant type even after its initial type declaration. For this, we offer extensible variant types.

Definition and Usage

ReScriptJS Output
type t = ..

type t += Other

type t +=
  | Point(float, float)
  | Line(float, float, float, float)

The .. in the type declaration above defines an extensible variant type t. The += operator is then used to add constructors to the given type.

Note: Don't forget the leading type keyword when using the += operator!

Pattern Matching Caveats

Extensible variants are open-ended, so the compiler will not be able to exhaustively pattern match all available cases. You will always need to provide a default _ case for every switch expression.

ReScriptJS Output
let print = v =>
  switch v {
  | Point(x, y) => Js.log2("Point", (x, y))
  | Line(ax, ay, bx, by) => Js.log2("Line", (ax, ay, bx, by))
  | Other
  | _ => Js.log("Other")
  }

Tips & Tricks

Fun fact: In ReScript, exceptions are actually extensible variants under the hood, so exception UserError(string) is equivalent to type exn += UserError(string). It's one of the very few use-case where extensible variants make sense.

We usually recommend sticking with common variants as much as possible to reap the benefits of exhaustive pattern matching.