Chapter 1: Why TypeScript?
Version: TypeScript 5.8 · Node.js 24 LTS
JavaScript lets a wrong value slip through and break your program later, in a place far from the mistake. TypeScript is JavaScript plus type checking, so the mistake gets stopped while you are still writing the code.
First, what is JavaScript?
JavaScript is the programming language of the web: it is what makes pages react when you click, type, and scroll, and it also runs on servers through a program called Node.js. When you write JavaScript, you create values (text, numbers, lists, and pieces of code called functions) and combine them to get work done. TypeScript starts from exactly this language and adds one thing: a checking step before your program runs.
A small bug that runs happily
Look at this plain JavaScript function. It adds two numbers:
function add(a, b) {
return a + b;
}
console.log(add(2, 3));
console.log(add("2", 3)); Run it and you get:
5
23 The first line is correct: 2 + 3 is 5. The second line is a bug. The caller passed "2" — text in quotes — instead of the number 2. JavaScript did not complain. With text involved, the + operator glues pieces together instead of adding, so "2" and 3 became the text "23" , printed as 23.
Nothing crashed. No warning appeared. The program kept running with a wrong answer, and in a bigger program that wrong answer would travel: into a total price, a saved record, a report someone trusts. Bugs like this are expensive because you find them late, and the place where they surface is rarely the place where they were made.
Why does JavaScript allow this? Because in JavaScript a parameter like a accepts anything — a number, text, a list, nothing at all. The language checks almost nothing ahead of time. You only find out about a mismatch when the program runs, if you find out at all.
The same function, with types
Here is the same function written in TypeScript. The two additions are : number after each parameter and : number after the closing parenthesis:
function add(a: number, b: number): number {
return a + b;
}
console.log(add(2, 3));
5 So far it behaves the same. The difference appears when the bad call comes back:
function add(a: number, b: number): number {
return a + b;
}
console.log(add("2", 3)); This time the program does not run at all. The TypeScript compiler stops it and prints this error:
error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. Read it slowly, because you will see this shape of error a lot. It says: you passed an argument of type string (text), and that does not fit a parameter of type number . The mistake is caught at the exact line that made it, before a single line of the program executes. That is the whole idea of TypeScript in one example.
In JavaScript the wrong call runs and prints 23. In TypeScript the compiler rejects it with error TS2345.
What a type annotation is
The : number pieces are called type annotations. An annotation is a label you write after a name to say what kind of value belongs there:
const message: string = "Hello, TypeScript!"; Read it as: message is a string — a piece of text — and its value is "Hello, TypeScript!" . Once a name has a type, the compiler enforces it. Assign text to a number , pass a number where a string belongs, and you get an error like the one above, naming both types involved.
Annotations are promises you make to the compiler, and the compiler holds everyone to them: you, your future self, and anyone else who calls your functions. A function signature like add(a: number, b: number): number is a small contract: numbers go in, a number comes out. Nobody has to guess, and nobody has to read the function body to find out.
NOTE TypeScript's word for text is string , and there is one number type for whole numbers and decimals alike. You will meet string , number , and boolean (true/false) formally in the next chapter.
TypeScript compiles to JavaScript
Browsers and Node.js cannot run TypeScript directly. They run JavaScript. So a TypeScript program goes through a compiler, tsc , which does two jobs:
- It checks every type in your code and reports mistakes.
- It rewrites your code as plain JavaScript, with all the annotations removed, and hands that JavaScript over to run.
You write .ts, tsc checks it and produces .js, and Node or the browser runs the .js.
This has a consequence worth remembering: types exist only while you write and compile. At run time there are no types left, so TypeScript cannot catch a bad value that arrives while the program is already running — for example, text a user types into a form. What it catches, it catches early and precisely: the mistakes sitting in your own code.
Installing TypeScript
You need two things: Node.js (version 24 LTS is used in this book) and the TypeScript compiler. Check Node first:
$ node --version
v24.20.0 Then install TypeScript with Node's package manager, npm. The -g flag makes the tsc command available everywhere on your machine:
$ npm install -g typescript Check that it worked:
$ tsc --version
Version 5.8.3 That is all the setup there is. No project folders, no configuration files yet. One command and the compiler is installed.
GOTCHA If tsc is reported as "not found" right after installing, close and reopen your terminal. A freshly opened terminal picks up the new command; an old one often does not.
Your first TypeScript program
Create a file named hello.ts with this inside:
const message: string = "Hello, TypeScript!";
console.log(message); Compile it:
$ tsc hello.ts When the types are clean, tsc prints nothing at all. Silence means success. It does leave something behind, though: a new file, hello.js , sitting next to hello.ts . Open it and you will see the compiled output of your first program:
var message = "Hello, TypeScript!";
console.log(message); Two things to notice. First, the : string annotation is gone — the compiler checked it, used it, and then erased it, exactly as the pipeline diagram showed. Second, const became var , because a bare tsc run with no configuration aims at an older JavaScript style. Later in this book you will set up a configuration file that keeps the output modern; for now, the point is that the code works. Run it with Node:
$ node hello.js
Hello, TypeScript! You have written, type-checked, compiled, and run a TypeScript program.
PRO TIP Keep the .ts file as your source of truth. Never edit the .js output by hand — it gets overwritten on the next compile, and your edit disappears.
The feedback loop
Working in TypeScript settles into a short loop:
- Write a little code, with annotations where they help.
- Compile with tsc . If there are errors, read the first one: it names the file position, the type you gave, and the type that was expected.
- Fix that one error and compile again. Errors often cascade from a single cause, so one fix can clear several messages.
- Run the compiled JavaScript with Node and check the output against what you expected.
This loop is where the value lives. In plain JavaScript, step 2 barely exists: a type mistake passes silently and shows up in step 4, if at all, as a wrong result you have to trace backwards. In TypeScript the compiler points at the wrong line and names the mismatch. The loop feels slightly stricter at first, and then it starts saving you real time — the compiler answers questions ("what kind of value is this, really?") that you would otherwise answer by hunting through your own code.
One habit to build from day one: when an error appears, fix the code, not the type. Beginners sometimes silence an error by widening a type until the compiler stops complaining, which throws away the protection the type was giving. The error is usually right. Trust it, read it twice, and change the value that is actually wrong.
Try It Yourself
- Write a program that stores your favourite course name in a string variable called course and prints the
sentence I am learning TypeScript! using that variable (use the word TypeScript as the value).
Answer
const course: string = "TypeScript";
console.log("I am learning " + course + "!");
I am learning TypeScript! - Write a typed function addTen that takes a number , returns a number , and gives back the value plus 10.
Print the result of calling it with 5.
Answer
function addTen(value: number): number {
return value + 10;
}
console.log(addTen(5));
15