The Basics

The compiler tsc does two independent jobs: it checks your program against the types it can see, and it emits JavaScript with the types removed. Keeping those jobs apart in your head explains most of TypeScript's behavior.

Static checking

In JavaScript, user.nmae is simply undefined and Math.random < 0.5 quietly compares a function with a number (Types). The checker reads the source without running it and reports such non-exception failures.

Four bugs that JavaScript runs silently and tsc rejectsJavaScript
const user = { name: "Ada", born: 1815 };
function age(person: { born: number }, year) {
  return year - person.born;
}
console.log(user.nmae);                        // typo
if (Math.random < 0.5) console.log("heads");   // forgot the ()
const box = document.querySelector("input");   // may be null
box.value = String(age(user, 2026));
Output
basics.ts(3,40): error TS7006: Parameter 'year' implicitly has an 'any' type.
basics.ts(6,18): error TS2339: Property 'nmae' does not exist on type '{ name: string; born:
  number; }'.
basics.ts(7,5): error TS2365: Operator '<' cannot be applied to types '() => number' and
  'number'.
basics.ts(9,1): error TS18047: 'box' is possibly 'null'.
Erased types

Run npx tsc basics.ts and you still get basics.js, with the annotations deleted and "use strict"; on top: tsc emits despite errors unless you pass --noEmitOnError. Erased types never change what the program does, and you cannot test a type at runtime; narrowing (Narrowing) relies on ordinary JavaScript checks. Erasure is also why Node.js 2,131 can run .ts files directly (Installing and Running); --erasableSyntaxOnly rejects the few constructs that emit code, such as enum and constructor parameter properties.

Downleveling

The target option names the ECMAScript version the output may use; newer syntax is rewritten. Since TypeScript 6.0 the default is es2025, so modern code passes through unchanged. ES2015 is now the floor: TypeScript 7 answers --target es5 with error TS5108: Option 'target=ES5' has been removed.

Optional chaining, ?? and ** compiled with --target es2015Shell
export function retries(opts?: { max?: number }): number {
  const max = opts?.max;
  return max ?? 2 ** 3;
}
Output
export function retries(opts) {
    const max = opts === null || opts === void 0 ? void 0 : opts.max;
    return max !== null && max !== void 0 ? max : Math.pow(2, 3);
}

Downleveling rewrites syntax only; it does not add missing library functions such as Array.prototype.findLast.

Strictness

strict, on by default since TypeScript 6.0, switches on nine checks, chiefly noImplicitAny (the first error above) and strictNullChecks (the last); with --strict false only the middle two errors remain. Keep it on for new code; when migrating JavaScript, relax single flags in tsconfig.json (Project Configuration) and restore them gradually.