Command Palette

Search for a command to run...

Hectal
PHASE 1Beginner ~19 min· topic 1 of 7

Topic 1.1

Type Annotations

In one line

A type annotation is a colon and a type written after a name (age: number). It is a promise the checker holds you to on every line that uses the name.

Think of it like this

A label on a storage box. A box labelled "batteries" tells everyone what belongs inside, and if someone drops a banana in, you notice the mistake straight away. An annotation is that label. You write : number after a name, and from then on the checker looks at every place that name is used and complains when a banana shows up.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

Annotation
The : type you write after a name to say what kind of value it holds.
Parameter
A name in a function's brackets that receives a value when the function is called.
Argument
The actual value you pass for a parameter when you call the function.
Return type
The type of the value a function hands back, written after the closing bracket as : type.
Assign
To store a value in a name with =. The value must fit the name's type.
Assignable
A value is assignable to a type when it fits there. The message "Type 'string' is not assignable to type 'number'" means a string can't be stored where a number is promised.
Compile time
The moment the checker reads your code, before it runs. Annotation errors appear here.
Erased
Removed. Annotations are deleted when the code becomes JavaScript, so they never exist at runtime.
TS code
The number after TS in an error (like TS2322). It names the kind of error and never changes.

Step by step

01Name, colon, type

Start with the smallest piece. After the variable's name, add a colon and the type.

string is text, number is any number (whole or decimal) and boolean is true or false. These three are written in lower case.

variables.tswhole filets
let city: string = "Pune";
const year: number = 2026;
let done: boolean = false;

02Annotate a function: parameters and result

Each parameter gets its own annotation. The return type goes after the closing bracket.

Now the signature (the first line) says everything a caller needs: area takes two numbers and gives a number. Hover over the name in your editor and you see exactly that line.

area.tswhole filets
function area(width: number, height: number): number {
  return width * height;
}

const double = (n: number): number => n * 2;

03What the checker does with a promise

Whenever a value flows into an annotated name, the checker asks one question: does this value fit the type?

Assigning "ten" to score: number fails with TS2322 (Type 'string' is not assignable to type 'number'). Returning a number from a function that promised a string fails the same way, on the return line.

What the checker does with a promisediagram
Rendering diagram…

04Where errors point

An error line looks like index.ts(5,3): error TS2322: .... Read it as: file index.ts, line 5, column 3, error code TS2322, then the message.

The position is where the broken promise happens: for a wrong return value it is the return itself. You will use this to find the real cause quickly.

05Annotations are erased

When TypeScript writes the JavaScript, every annotation is cut out. Nothing about it remains for the browser.

That is also why code with a type error still runs in the live examples: the checker complains, the JavaScript that is left does its best, and the console shows what actually happened.

area.js (what runs)whole filejs
function area(width, height) {
  return width * height;
}
const double = (n) => n * 2;

Try it yourself

  1. 1

    Fix the return

    In the second example, change : string on label to : number. Predict what happens to the second error before you look.

    It disappears, because now the promise matches the value. Either side can be the wrong one: first decide whether the promise or the value is what you meant.

  2. 2

    Call it wrongly

    In the first example add the line area("3", 4);. Which column does the error point at, and what does the message say the expected type was?

  3. 3

    Delete a promise

    Remove : number from the double arrow function's parameter, so it reads (n): number => n * 2. A new kind of error appears; the message ends with "implicitly has an 'any' type". That is the rule from the walkthrough: parameters need your help.

Code & diagrams

Annotations on variables, a function and an arrow function

Hover answers appear in the Types panel. Notice that year is shown as number: you annotated it, so TypeScript uses your type. Without the annotation it would be the exact value 2026 (Topic 1.3).

Console

(nothing was printed)

Expected console output

Pune 2026 false
12 42
Two broken promises

Both errors are TS2322. The first points at the assignment, the second at the return statement. The JavaScript still runs and prints the wrong kinds of values: a string where a number was promised, and a number where text was promised.

Console

(nothing was printed)

Expected console output

ten 8

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Return the wrong kind of value

In the second example, label promises string but returns n * 2, a number.

terminal
$ Types panel
── what you'll see ──
index.ts(5,3): error TS2322: Type 'number' is not assignable to type 'string'.

Myth vs fact

Myth

Annotations change how the program runs.

Fact

They are deleted before the code runs. The same JavaScript would result without them; annotations only change what the checker allows.

Myth

You must annotate every variable.

Fact

Most variables are inferred correctly from their first value. Annotate parameters, and add others only when they help the reader or fix a wrong guess (Topic 1.3).

Myth

An annotation checks the value while the program runs.

Fact

It is checked once, by reading the code. At runtime nothing verifies that a number really is one; if bad data sneaks in (Topic 13.4), the annotation can't notice.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    The checker asks one question at every annotated position: is the source type assignable to the target type? Almost every error you will ever see is that question answered "no". The code TS2322 is the general form (assignment and return), TS2345 is the same question for a function argument.

  • ▸

    Because the annotation is erased, TypeScript can't use it to optimise anything. JavaScript engines don't see your types. Speed comes from the way you write the JavaScript, not from the types.

  • ▸

    Return annotations are also a performance and stability tool: on a public function an explicit return type stops a change deep inside the body from silently changing what callers see, and it lets the compiler skip re-deriving the type. Libraries enforce this with isolatedDeclarations (Topic 11.3).

Remember this

  1. 1

    The problem this solves: plain JavaScript happily lets a piece of text flow into a place that expects a number, and the mistake only shows up later, in front of a user. An annotation states what a name is supposed to hold, so the checker can stop the mistake before the program runs.

  2. 2

    The syntax is always the same: name, colon, type. let city: string = "Pune"; reads "city is a string, and it starts as Pune". The colon part is the type annotation. It exists only for the checker: when the program is turned into JavaScript the annotation is simply deleted, so it costs nothing at runtime (Topic 0.2).

  3. 3

    Annotations go in three main places. On a variable: let done: boolean = false;. On a parameter (a name a function receives): function area(width: number, height: number). And after the closing bracket of a function, for its return value: function area(...): number { ... }. Arrow functions work the same way: const double = (n: number): number => n * 2;.

  4. 4

    An annotation is a promise in two directions. Every value put into the name must fit the type (score = "ten" breaks the promise of score: number), and every use of the name may rely on the type (a number always has .toFixed(), but never .toUpperCase()). A return annotation promises the same for the function's result: if any return hands back the wrong kind of value, the error is reported on that return line, not on the caller, so you find the bug where it was made.

  5. 5

    A parameter annotation is the one you must usually write yourself. A function can be called from many places, so TypeScript can't work out what it will receive. With no annotation the parameter would be any ("anything goes"), and strict mode, which is on by default in new projects, refuses and reports TS7006 (Topic 0.1, Topic 1.6). That one rule is why you will write far more parameter annotations than any other kind.

  6. 6

    Types are written after the name, not before as in Java or C (int age). The reason is practical: in JavaScript a declaration begins with let, const or function, and TypeScript only adds an optional ending. Because of that, deleting every annotation always leaves valid JavaScript.

  7. 7

    You don't have to annotate everything. When you write let city: string = "Pune", the : string repeats what TypeScript already knows from the value. Topic 1.3 explains inference and a clear rule for when an annotation helps and when it is noise. For now: annotate parameters, usually annotate return values of exported functions, and let simple variables be inferred.

Explain it without notes

01

What is a type annotation and where can you write one?

02

Why do function parameters usually need annotations while many variables don't?

03

Are annotations present at runtime? What follows from the answer?

04

A function promises : string but one branch returns a number. Where does TypeScript report the error, and why there?

Practice

01

Write a function fullName that takes first and last (both text) and returns the two joined with a space. Annotate every parameter and the return value. Then call it with a number and write down the error.

02

This arrow function has no annotations. Add them so it takes a number of items and a price per item (both numbers) and returns the total as a number. ``ts const total = (count, price) => count * price;

Trade-offs

  • ↔

    More annotations make code self-explaining and catch changes early, but repeat what the compiler already knows and add noise. A good balance: annotate function boundaries, trust inference inside.

  • ↔

    A return annotation can be wider than the real result (you declare : string | null and always return text), which hides precision from callers. Annotate what you want to promise, not what you happen to return today.

Done when you can

  • I can write the name, colon, type form on a variable, a parameter and a return value.

  • I can say what a type annotation promises and in which two directions.

  • I can read index.ts(5,3): error TS2322: ... and find the line and column.

  • I can explain why annotations are free at runtime.

  • I can explain why parameters need annotations in strict mode.