Sostieni AppuntiFacili con una piccola donazione su PayPal
Dona con PayPalTypeScript is a programming language created by Microsoft that adds static types on top of JavaScript. It is often described as a superset of JavaScript: every valid JavaScript program is also (mostly) valid TypeScript, but TypeScript adds extra syntax to describe the shape of your data — types.
TypeScript code does not run directly in a browser or in Node.js. It gets compiled (we also say transpiled) down to plain JavaScript first. The type annotations exist only while you are writing and checking the code; by the time it runs, they are gone.
flowchart LR
A[TypeScript source .ts] --> B[TypeScript Compiler tsc]
B --> C[Type checking]
C --> D[Plain JavaScript .js]
D --> E[Runs in browser / Node.js]
TIP
Think of TypeScript as JavaScript with a spell-checker for your data. It doesn’t change how your program behaves at runtime — it changes how many mistakes you catch before runtime.
JavaScript is a dynamically typed language. This means a variable’s type is not fixed: it is decided at runtime, based on whatever value currently lives in it, and it can change freely during the program’s life.
let myVariable = 10; // number
console.log(myVariable);
myVariable = "Hello world!"; // now a string — perfectly legal in JS
console.log(myVariable);
Nothing stops you from reassigning myVariable to a completely different type. JavaScript does not check this while you write the code; it only ever cares about what is actually in the variable right now.
Compare this with statically typed languages, where a variable’s type is fixed when it is declared (or inferred) and cannot change afterward. TypeScript brings this discipline to the JavaScript world.
Another key difference is when errors are detected.
Consider this JavaScript file:
function test() {
}
test()(); // calling the result of test() as if it were a function
If you run this with node demo.js, Node.js starts executing line by line. There is nothing wrong with defining test, so nothing fails yet. Only when the engine reaches test()() does it discover the problem: test() returns undefined (a function with no return statement returns undefined by default), and then the code tries to call undefined as if it were a function. This throws a runtime TypeError: test(...) is not a function.
WARNING
In JavaScript this bug is invisible until the exact line runs. In a large program, a rarely executed code path (an if branch that only triggers in production, for example) can hide bugs like this for a long time.
TypeScript would catch this immediately while you are typing the code, because it can see that test has a return type of void (nothing) and void is not callable — no need to ever run the program.
JavaScript is very permissive about mixing types in expressions:
function test() {
}
const result = test + 2;
console.log(result); // "function test() {\n}2" — a string!
What happens here? JavaScript needs a single value out of +, so it converts both operands to a common type. Since one operand is a function (not a number), JavaScript falls back to string coercion: it calls test.toString() (which produces the function’s source code as text) and concatenates it with "2". The result is a nonsensical string, produced silently, with no error at all.
TypeScript rejects this at compile time: a function value and a number simply cannot be combined with +, and the compiler tells you so before you ever run the code.
DANGER
This is the real cost of pure dynamic typing: not that errors happen, but that some “errors” don’t even look like errors — they just quietly produce garbage data, like the string above.
In a dynamically typed language:
In a statically typed language:
TypeScript’s whole value proposition is to give you both: you keep writing JavaScript, with all its flexibility and its enormous ecosystem, but you annotate your code with types so the compiler can catch mistakes early, while your editor gains autocomplete, inline documentation, and safe refactoring.
tsc) performs type checking and then emits plain JavaScript — types are erased, they never exist at runtime.if (typeof x === MyInterface) — interfaces don’t exist at runtime).INFO
TypeScript doesn’t replace JavaScript — it compiles to JavaScript. Any JS runtime (browsers, Node.js, Deno, Bun…) can run the output without knowing TypeScript ever existed.
What best describes TypeScript's relationship with JavaScript?
In the example `function test() {} test()();`, why does this fail at runtime in plain JavaScript?
What happens when you evaluate `test + 2` in JavaScript, where `test` is a function?
What is the key difference between a dynamically typed and a statically typed language?
What happens to TypeScript's type annotations when the code is compiled?
Why is an interpreted language often described as 'more flexible' than a compiled one?
Scenario: You are onboarding a new teammate who has only ever written JavaScript, and they are skeptical about “adding extra syntax that does nothing at runtime.”
Task:
.js file that reproduces the test()() bug from this lesson, run it with Node.js, and observe the runtime TypeError.test + 2 string-coercion oddity, and log the result to see the nonsensical string.Learning objective: understand the practical difference between a runtime error caught late and a compile-time error caught early, and connect this to the core motivation for using TypeScript.
Prenota una lezione