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:
let name = "hem"
let mut count = 0
count += 1Destructuring 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:
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 }
}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:
let x = 5
let printX = () => console.log(x)
let x = 6
printX()const x = 5;
const printX = () => console.log(x);
const x$1 = 6;
printX();