Type annotations
What you'll learn:
- write the type of a variable, a parameter and a function's result;
- tell where TypeScript infers a type on its own and where you have to write it;
- explain why
let a = 5gets the typenumberwhileconst b = 5gets the literal type5; - tell a
constthat forbids a new value apart from an object that cannot change.

Picture a kitchen shelf of jars. Each jar has a label: "Salt", "Sugar", "Buckwheat". The label says what may go into the jar before anyone opens it. If someone starts pouring sugar into the jar labeled "Salt", the mistake is noticed at once, not when the soup turns out sweet.
JavaScript variables have no such labels. Today price holds a number, tomorrow someone writes the string "free" into it, and the program breaks somewhere else entirely—where price.toFixed(2) is called. To find the cause, you have to walk back through the code and look for who put a string there, and when.
In TypeScript you can write the label yourself. A type annotation is : type written after a name; it tells the compiler which type of values is allowed there. The colon reads as "has the type": count: number means "count has the type number".
Three places for an annotation
An annotation goes in three places: on a variable, on a function parameter and on a function's result. This example has all three:
let count: number = 0;
function withDelivery(price: number): number {
return price + 300;
}
count = count + 1;
console.log(count, withDelivery(1200)); // 1 1500The program compiles without errors and prints 1 1500. Let's take each place in turn.
A variable
The line let count: number = 0; has three parts:
let count—an ordinary declaration, as in JavaScript;: number—the annotation: only numbers may be written intocount;= 0—the initial value, which must be a number too.
From then on, the compiler checks every assignment against the label. count = count + 1 puts a number into a number variable, and the check passes. The line count = "two" would give error TS2322, which you already met in the first theme.
A function parameter
price: number inside the parentheses is a label on the function's input. To the function body it promises that price holds a number, and it requires whoever calls the function to pass exactly a number:
function withDelivery(price: number): number {
return price + 300;
}
withDelivery("1200"); // ✗error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.The message means: "an argument of type string cannot be passed to a parameter of type number". tsc reports the error on the line of the call, although the function is declared above it. If JavaScript ran this call, "1200" + 300 would join the strings, and you would get "1200300" instead of 1500.
A function's result
The annotation after the parameter list—): number—is a label on the output. The function promises to return a number, and the compiler checks every return in its body:
function withDelivery(price: number): number {
return "Итого: " + (price + 300); // ✗
}error TS2322: Type 'string' is not assignable to type 'number'.The error sits on the line with return: a function that promised a number cannot return a string. You don't have to search the calls of withDelivery for the cause—the error shows where the promise is broken.
Who reads the labels
This is where the jar analogy ends. A label on a jar can be overlooked, while tsc checks an annotation every time it compiles the file. But the JavaScript it writes no longer has annotations: when the program runs, nobody checks the types.
Common mistake
The annotation is taken for a conversion, and the string is expected to become a number:
let quantity: number = "5"; // ✗error TS2322: Type 'string' is not assignable to type 'number'.An annotation converts nothing; it only checks. A string, say from a form field, is first turned into a number—Number("5")—and then the result goes into a variable of type number.
Key points
- A type annotation is
: typewritten after a name; the colon reads as "has the type". - An annotation goes on a variable (
let count: number), a parameter (price: number) and a function's result (): number). tscchecks every assignment, every call and everyreturnagainst the annotation.- An annotation converts nothing: the string
"5"cannot be written into a variable of typenumber.