0% completed
Understanding Static Typing
On This Page
What Is Static Typing?
What the Compiler Does With a File
Why Static Typing Helps
What Static Typing Does Not Check
let price: number = 20; price = "twenty";
price.ts(2,1): error TS2322: Type 'string' is not assignable to type 'number'.
The compiler reported the second line without running the program. It knows that price must hold a number, it sees a string being assigned, and it reports the mismatch.
What Is Static Typing?
When the types of variables are known and checked at compile time, rather than at runtime, the language uses static typing. Compile time is the moment when the compiler reads your code, and runtime is the moment when the program executes. TypeScript has stricter rules than JavaScript here, because the compiler accepts only values of the declared type for a declared variable.
JavaScript performs no such check, so the same assignment is allowed:
let price = 20; price = "twenty"; // No error in JavaScript, even though price started as a number
What the Compiler Does With a File
Install the compiler in a project, and then you can run it on a file. The command name is tsc:
npm install --save-dev typescript npx tsc order.ts
Suppose order.ts holds the calculateTotal function from the previous chapter, with a wrong second argument:
function calculateTotal(price: number, shipping: number): number { return price + shipping; } console.log(calculateTotal(5, "10"));
The compiler handles this file in a fixed order. First, it reads order.ts, checks every type, and reports the problem it found:
order.ts(5,31): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
Next, it removes all the types, and it writes order.js anyway. The first line, which the compiler adds, turns on the ECMAScript strict mode from the previous chapter:
"use strict"; function calculateTotal(price, shipping) { return price + shipping; } console.log(calculateTotal(5, "10"));
Finally, you run node order.js. The program joins the two values as strings instead of adding them, because nothing checks the types at runtime:
510
A type error therefore does not stop the JavaScript file from being written. The error tells you that the code is wrong, and the command fails with a nonzero exit code, so a build script can stop at that point. If you want no output file at all when there are errors, use the compiler option noEmitOnError.
In the next picture, notice that the type annotations are present before the compiler and absent after it. Removing types in this way is called type erasure.
No tsconfig.json file was needed here. If the folder already has one, npx tsc order.ts stops with error TS5112 and writes nothing, because a file named on the command line does not use that configuration. In that case, add the flag --ignoreConfig, or run the example in an empty folder.
Current TypeScript also turns on strict, a group of stricter checks, by default. Older projects and older compiler versions may have it off, so check the tsconfig.json file of any project that you join.
Why Static Typing Helps
It catches errors early. You saw the compiler find the "10" argument before the program ran. In a large JavaScript application, the same mistake produces the output 510 somewhere in the program, and it can take a long time to trace that value back to its cause.
It makes code easier to read and maintain. Compare the two versions of the function. In the JavaScript version, a developer cannot tell whether price and shipping should be numbers, strings, or something else:
function calculateTotal(price, shipping) { return price + shipping; }
The TypeScript signature states that both parameters are numbers and that the return value is also a number. This works as documentation, and the compiler keeps it accurate:
function calculateTotal(price: number, shipping: number): number { return price + shipping; }
It improves autocompletion. Editors such as VS Code know the type of each value, so they can suggest correct property names and report wrong ones as you type. The next example uses an interface, which gives a name to the shape of an object. The chapter on object types covers interfaces in detail.
interface User { id: number; name: string; } const user: User = { id: 1, name: "Alice" }; console.log(user.age);
user.ts(8,18): error TS2339: Property 'age' does not exist on type 'User'.
If this line ran as JavaScript, it would not crash. It would print undefined, and the crash would come later, for example TypeError: Cannot read properties of undefined (reading 'toFixed') when some other code called user.age.toFixed(). The compiler reports the wrong property at the line that contains the mistake.
It makes refactoring safer. Suppose you rename the name property of User to fullName. Every line that still reads user.name now produces an error, so the compiler gives you a list of places to change. In JavaScript, each of those lines would quietly produce undefined.
What Static Typing Does Not Check
Static typing reduces runtime errors, but it does not remove them, because the compiler sees only your source code. It cannot see the data that arrives while the program runs. Here the price comes from a JSON string, and JSON.parse returns the type any, which turns off checking for that value:
function calculateTotal(price: number, shipping: number): number { return price + shipping; } const input = JSON.parse('{"price":"20"}'); console.log(calculateTotal(input.price, 5));
205
This file compiles with no errors, and it still prints the wrong total. Data from outside the program needs a check in your own code at runtime, and the chapter on advanced types shows how to write one.
Reading Progress
0%
On This Page
What Is Static Typing?
What the Compiler Does With a File
Why Static Typing Helps
What Static Typing Does Not Check