Var Scope
var vs let/const scoping.
let/const are block-scoped: a binding declared inside { ... } (or a loop or if body) is not visible after that block. var is function-scoped: it "leaks" out of the block it was declared in and stays visible for the rest of the enclosing function. See
// --- var leaks out of a plain block ---
function leaks(): void {
{ var inner = 5 }
console.log(inner) // 5 (var is visible after the block)
}
leaks()
// --- a for-loop's var counter leaks too ---
function counter(): void {
for (var i = 0; i < 3; i = i + 1) {}
console.log(i) // 3 (i survives the loop)
}
counter()
// --- var may be re-declared with the same name; the later one just wins ---
var total = 1
var total = 2
console.log(total) // 2
// --- a var read on a control-flow path where it was never assigned ---
// An any-typed var reads back as undefined (like JS); a typed var reads a
// deterministic zero default rather than uninitialized memory.
function maybe(flag: boolean): void {
if (flag) { var got: any = 42 }
console.log(got) // undefined (flag is false, so the assignment never ran)
}
maybe(false)
// --- let/const stay block-scoped (the counterpart to var above) ---
function blockScoped(): void {
let a = 10
{
let a = 20 // a different binding, shadowing the outer a
console.log(a) // 20
}
console.log(a) // 10 (outer a is unchanged)
}
blockScoped()
// --- top-level scalar/string const/let are module globals: a named function
// (not just a capturing arrow) can read and write them (TDD-00093) ---
const APP = "demo"
let hits = 0
function greet(): void {
hits = hits + 1 // a named function mutates the module let
console.log("hello from " + APP)
}
const report = (): void => {
console.log("hits=" + hits) // an arrow sees the same global, live
}
greet()
greet()
report() // hits=2 (the mutation is shared, not a copy)View source on GitHubexamples/basics/var-scope.ts