A | B is an anonymous closed union of types.
fn decode(input: string): int | string {
if input == "answer" {
return 42
}
return input
}Unlike a named enum, the alternatives are the member types themselves.
Injection
A value of a member type can flow into an expected union.
value: int | string = 42This is a checked union injection. It does not make unrelated types generally assignable to one another.
Branch inference can synthesize a union when normally completing branches produce incompatible closed types.
fn choose(flag: bool) {
if flag { 1 } else { "one" }
}State an explicit return type when that union is part of a public API.
Canonicalization
Anonymous unions are structural and canonicalized:
- member order does not create a different type;
- duplicate members collapse;
- nested anonymous unions flatten.
Conceptually, A | B, B | A, and A | (B | A) describe the same union.
Matching
For nominal member types, use type-name patterns.
struct NumberValue { value: int }
struct TextValue { value: string }
fn show(value: NumberValue | TextValue): string {
return match value {
NumberValue(number) => "${number.value}"
TextValue(text) => text.value
}
}For scalar or other type groups, bind the value with name: Type.
fn describe(value: int | string): string {
return match value {
number: int => "number: $number"
text: string => "text: $text"
}
}The match checker knows the union’s complete member set.
Shared fields
Field access can be valid across a union when every constituent exposes a compatible field.
struct Person { id: int, name: string }
struct Device { id: int, serial: string }
fn identifier(value: Person | Device): int {
return value.id
}If any member lacks the field or gives it an incompatible type, direct access is rejected. Match the alternatives instead.
Method dispatch across a union similarly requires every constituent to support a compatible method.
Distinct unions
Two anonymous unions with the same member set are the same structural type. Wrap one in a distinct alias when domain identity must remain separate.
distinct type InputValue = int | string
distinct type OutputValue = int | stringThe two aliases no longer interchange implicitly even though their representations use the same member types.
Choosing enums
Use a named enum when:
- alternatives need stable variant names;
- several alternatives use the same payload type;
- payload fields need variant-specific names;
- behavior or derives belong to the sum type;
- the domain should remain distinct from another structurally equal set.
Use an anonymous union for a local closed combination of already meaningful types.
Option[T], Result[T, E], and declared error unions have additional
construction and propagation rules and are documented under Errors.