Skip to content

Define a refined type and validate untrusted input

Goal: constrain a value with a predicate, then safely admit a value that is not known until runtime.

Write a base type followed by where and one or more predicates (combine them with and):

commons signup {
type Age = Int where InRange(0, 150)
type Username = String where MinLength(3) and MaxLength(20)
}

For the full predicate list, see the refined-type reference.

The base may be Int, Float, or String. Float is a distinct primitive — it never coerces to or from Int — and takes float bounds:

commons pricing {
type Ratio = Float where InRange(0.0, 1.0)
type Price = Float where Positive
}

Untrusted input must be checked at runtime. Every refined type has an .of constructor that returns a Result:

fn parseAge(raw: Int) -> Result[Age, ValidationError] {
Age.of(raw)
}

Age.of(raw) returns Ok(age) if raw satisfies the predicate, or Err(validationError) otherwise.

Propagate the error with ? inside a function that returns a Result:

fn register(name: String) -> Result[Username, ValidationError] {
let u = Username.of(name)?
Ok(u)
}

…or branch on both cases with match:

fn label(raw: Int) -> String {
match Age.of(raw) {
Ok(a) => "valid age"
Err(e) => "invalid age"
}
}