Skip to content

Syntax Reference

// Line comment
/* Block comment */
/* Nested /* block */ comments */
const x = 42
const name: string = "hello"
export const PI = 3.14159
// Destructuring
const [a, b] = pair
const { name, age } = user
fn name(param: Type) -> ReturnType {
body
}
export fn name(param: Type) -> ReturnType {
body
}
async fn name() -> Promise<T> {
await expr
}
// Record
type User {
name: string,
email: string,
}
// Union
type Shape {
| Circle { radius: number }
| Rectangle { width: number, height: number }
}
// Newtype (single-value wrapper)
type OrderId { number }
// String literal union (for npm interop)
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE"
// Alias
type Name = string
// Brand
type UserId = Brand<string, "UserId">
// Opaque
opaque type Email = string
// Deriving traits
type Point {
x: number,
y: number,
} deriving (Display)
// Block form: group multiple functions
for Type {
fn method(self) -> ReturnType {
body
}
}
// Inline form: single function, no block
export for Type fn method(self) -> ReturnType {
body
}
for Array<User> {
fn adults(self) -> Array<User> {
self |> Array.filter(.age >= 18)
}
}
42 // number
3.14 // number
1_000_000 // number with separators (underscores for readability)
3.141_592 // float with separators
0xFF_FF // hex with separators
"hello" // string
`hello ${name}` // template literal
true // boolean
false // boolean
[1, 2, 3] // array

Underscores in number literals are purely visual — they are stripped during compilation. They can appear between any two digits but not at the start, end, or adjacent to a decimal point.

a + b a - b a * b a / b a % b // arithmetic
a == b a != b a < b a > b // comparison
a <= b a >= b // comparison
a && b a || b !a // logical
a |> f // pipe
expr? // unwrap
value |> transform
value |> f(other_arg, _) // placeholder
a |> b |> c // chaining
value |> match { ... } // pipe into match
match expr {
pattern -> body,
pattern when guard -> body,
_ -> default,
}
// Pipe into match
expr |> match {
pattern -> body,
_ -> default,
}

Patterns: literals (42, "hello", true), ranges (1..10), variants (Ok(x)), records ({ x, y }), string patterns ("/users/{id}"), bindings (x), wildcard (_).

f(a, b)
f(name: value) // named argument
Constructor(a: 1) // record constructor
Constructor(..existing, a: 2) // spread + update
collect {
const name = validateName(input.name)?
const email = validateEmail(input.email)?
ValidForm(name, email)
}
// Returns Result<T, Array<E>> — accumulates all errors from ?
Ok(value) // Result success
Err(error) // Result failure
Some(value) // Option present
None // Option absent
todo // placeholder, type never, emits warning
unreachable // assert unreachable, type never
parse<T>(value) // runtime type validation, returns Result<T, Error>
json |> parse<User>? // pipe form (most common)
data |> parse<Array<Product>>? // validates arrays
Filter.All // zero-arg variant
Filter.Active // zero-arg variant
Option.Some(value) // variant with data
Result.Ok(value) // variant with data
fn(a, b) a + b
fn(x) x * 2
fn() doSomething()

Dot shorthand for field access:

.name // fn(x) x.name
.id != id // fn(x) x.id != id
.done == false // fn(x) x.done == false
fn() -> () // takes nothing, returns nothing
fn(string) -> number // takes string, returns number
fn(number, number) -> boolean // takes two numbers, returns boolean
<Component prop={value}>children</Component>
<div className="box">text</div>
<Input />
<>fragment</>
import { name } from "module"
import { name as alias } from "module"
import { a, b, c } from "module"
// Import for-block functions by type
import { for User } from "./helpers"
import { for Array, for Map } from "./collections"
// Mix regular and for-imports
import { Todo, Filter, for Array } from "./todo"
42 // literal
"hello" // string literal
true // boolean literal
x // binding
_ // wildcard
Ok(x) // variant
Some(inner) // option
{ field, other } // record destructure
1..10 // range