Type
record Type
Types as values.
Type.of(x) answers what a value IS, as something you can hold, print, compare, and take apart:
Type.of(42) # Type { name: "Integer", args: [] }
Type.of([1, 2]).toString # "[Integer]"
Type.of(x) == Type.of(y) # structural equality, like any record
Type.of(due).fields # ["year", "month", "day"]
The answer comes from the compiler where it can: a checked expression knows things a value cannot carry, such as the unused half of a Result or the element type of an empty list. Where the checker has no concrete answer — gradual code, --no-check, a value arriving from another process — the value itself is asked instead. That fallback is honest but lossy: an empty list has no element to inspect, and a Result only ever holds one side.
Fields
Methods
Everything else is a METHOD, not a module function: a module function is only reachable through UFCS in the interpreter, so Type.of(x).fields worked there and raised on BEAM.
module Type
named
named(name: String) -> Type
Builds a type by name, for comparing against something you already know: Type.of(x) == Type.named("Date").
generic
generic(name: String, args: [Type]) -> Type
The same, for a type that takes arguments: Type.of([1]) == Type.generic("List", [Type.named("Integer")]). Renamed from Type.with when with became the capability-substitution keyword (kexhq/kex#143).
function
function(params: [Type], result: Type) -> Type
A function type: parameters followed by the result, the way a signature is written — Type.function([Type.named("String")], Type.named("String")).
returnedBy
returnedBy(function: Any) -> Type
The type a named function returns, answered by the compiler:
Type.returnedBy(Date.parse).toString # "Result<Date, TimeError>"
Named functions only. A lambda or a function VALUE carries no signature at runtime, and an overloaded name has no single answer — both are compile errors rather than a guess.