Skip to content

Bindings ​

let name = expr names a subexpression inside a block so it can be reused — Typeflow's take on JSONata's $x := .... Bindings are immutable and don't appear in the output; they exist only to avoid repetition and make intent clear.

OperatorEffect
let name = exprname a subexpression for reuse
block scopebindings reach into nested blocks
declaration ordera binding sees only earlier bindings

let name = expr : name a subexpression for reuse ​

A let binding is visible to every property of its block. It computes once and reads as an ordinary identifier — total: base + tax instead of repeating the underlying paths.

typeflow
let base = order.subtotal
let tax = base * 0.2
total: base + tax

block scope : bindings reach into nested blocks ​

A binding is scoped to its block and every nested block within it, so a projection body (or a nested object) can add its own bindings and still see the outer ones.

typeflow
lines: order.items -> {
  let net = price * qty,
  net: net,
  withTax: net * 1.2,
}

declaration order : a binding sees only earlier bindings ​

All of a block’s properties may use any of its bindings, but a binding may only reference bindings declared before it — forward and self references are rejected (TF2001), so mappings stay terminating. Two bindings with the same name in one block is an error (TF2018).

typeflow
let base = order.subtotal
let withTax = base * 1.2

Playground ​

Mapping✔Playground ↗
Input JSON
Output
{
  "subtotal": 100,
  "tax": 20,
  "total": 120,
  "lines": [
    {
      "net": 20,
      "withTax": 24
    },
    {
      "net": 20,
      "withTax": 24
    }
  ]
}
inferred type{ subtotal: number; tax: number; total: number; lines: { net: number; withTax: number }[]; }

For logic you want to reuse across mappings — not just within one block — reach for a function instead: fn for pure mapping-language helpers, use for typed host functions.

Released under the MIT License.