---
title: "Bindings"
image: "https://hem.run/social/hem.png"
---

> Documentation Index
> Fetch the complete documentation index at: https://hem.run/llms.txt
> Use this file to discover all available pages before exploring further.

# Bindings

Hem's `let` is TypeScript's `const`; `let mut` is TypeScript's `let`. In core Hem, writing `const` is an error with an editor quick fix to replace it with `let`:

```hem
let name = "hem"
let mut count = 0
count += 1
```

Destructuring works as in TS: `let { id, name } = user`, `let [head, ...rest] = items`. Annotations are TypeScript's type language, verbatim: `let port: number = 8080`. One deliberate divergence: object-type literals you write in Hem are readonly by default, and a per-field `mut` opts back into mutability, matching `let` and class fields.

**Shadowing is legal**: each new binding can have a different type. Here `port` goes from `?string` to `string` to `number`:

```hem title="port.hem"
let readPort = (env: Env): number => {
  let port = env.PORT
  let Some(port) = port else return 8080
  let port = Number.parseInt(port, 10)
  if Number.isNaN(port) { 8080 } else { port }
}
```

```ts emitted title="port.ts — generated"
const readPort = (env: Env): number => {
  const port = env.PORT;
  const _hemValue = port;
  if (_hemValue === null || _hemValue === undefined) {
return 8080;
  }
  const port$1 = _hemValue;
  const port$2 = Number.parseInt(port$1, 10);
  return Number.isNaN(port$2) ? 8080 : port$2;
};
```

For same-type steps, chaining or `|>` is usually clearer.

Shadowing creates a new binding; it does not mutate the old one. A closure keeps the binding it captured, so this logs `5`:

```hem title="capture.hem"
let x = 5
let printX = () => console.log(x)
let x = 6
printX()
```

```ts emitted title="capture.ts — generated"
const x = 5;
const printX = () => console.log(x);
const x$1 = 6;
printX();
```

Source: https://hem.run/tour/bindings/index.mdx
