docs / Language
Track Declarations
The &[] sugar for creating reactive cells: auto-tracked bindings, raw-cell bindings, and how the compiler rewrites reads and writes.
The `&[]` track-declaration syntax is Vesk's sugar for creating reactive cells — it combines cell creation with variable binding in a single statement.
Syntax
app/components/Counter.vsk
let &[count] = track(0); // count is the auto-tracked cell
const &[items] = track<string[]>([]); // works with const too
let &[total, rawTotal] = track(0); // rawTotal is the raw Tracked<number>
- The first name is the reactive value — reads inside effects or component bodies subscribe, writes schedule an update automatically.
- The optional second name is the raw cell object, used with `untrack()`, `peek()` or when passing the cell around.
- Each `&[]` creates its own cell; there is no multi-cell shorthand.
- `&[]` can only appear at the top level of a component body, or inside a `block()`/`effect()`/`root()` call.
How the compiler rewrites it
| User code | Compiled output |
|---|---|
| count | get(count) |
| count = 5 | set(count, 5) |
| count++ | set(count, get(count) + 1) |
| count + 1 | get(count) + 1 |
You never call `get()` or `set()` manually when using `&[]` bindings — the compiler inserts them for you. The `&[]` binding atom is parsed with `lazy: true` and becomes a `TrackDecl` IR node.
Derived cells
app/components/Price.vsk
component Price(props: { qty: number, unit: number }) {
let &[total] = derived(() => props.qty * props.unit);
<p>Total: {total}</p>
}
`total` is read-only — writing to it throws. The function re-runs whenever a tracked dependency read inside it changes.