@mellson the idea is to wrap the type in a module and use like this
module String25: {
type t
let make: string => Belt.Result.t<t, string>
} = {
type t = string
let make = a =>
a->Js.String.length <= 25
? Belt.Result.Ok(a)
: Belt.Result.Error("String must be 25 letters utmost")
}
let safeString: Belt.Result.t<String25.t, string> = String25.make("Some string")
The way in Rescript is to use a module, and use code to protect the values you are concerned about.
You can build type systems which can handle logic rules on types, but those systems are not present in ReScript (and arguably still somewhat of a research area). I know of at least 3 general variants:
Lattice based systems. See e.g., CUE for a use.
Refinement types
Dependent types
The tricky part of these systems are that you need the type check to happen at compile time. And you open the door for having general logic in the type system. So the type checker might run for a long time, perhaps not even terminate.