Pure
The `/** @pure */` annotation asserts a function is side-effect-free and referentially transparent, and the compiler ENFORCES it with a front-end pass — zero runtime/codegen cost, byte-identical output to an untagged function. Inside a @pure function the compiler rejects: mutating a parameter (or anything reachable from it), mutating a captured/global binding, I/O (console/fs/fetch/…), nondeterminism (Math.random/Date.now/new Date), and calling a function that is not itself @pure (purity is contagious).
It applies to a declaration, an arrow binding, and a function-expression binding — including capturing closures.
/** @pure */
function square(n: number): number {
return n * n;
}
/** @pure */
function scale(n: number, by: number): number {
return n * by;
}
// An arrow binding gets the same enforcement.
/** @pure */
const cube = (n: number): number => n * n * n;
// Local mutation is fine — only *observable* effects are constrained. This
// builds and mutates its own local, and returns a fresh array; it touches
// nothing the caller can see.
/** @pure */
function scaledSquares(xs: number[], by: number): number[] {
const out: number[] = [];
for (const x of xs) {
out.push(scale(square(x), by)); // out is local — mutating it is allowed
}
return out;
}
// Purity is contagious: scaledSquares may call square/scale only because they
// are themselves @pure.
console.log(square(6)); // 36
console.log(scale(7, 3)); // 21
console.log(cube(4)); // 64
console.log(scaledSquares([1, 2, 3], 10).join(",")); // 10,40,90
// Each of these, uncommented inside a @pure function, is a COMPILE ERROR:
//
// /** @pure */
// function bad(xs: number[]): number {
// xs.push(1); // mutating method on a parameter
// console.log("hi"); // I/O
// return Math.random(); // nondeterminism
// }View source on GitHubexamples/jsdoc/pure.ts