# Type Annotations In Action

## Type Annotations and Type Inference

A **type annotation** is an *explicit* bit of code that tells TypeScript what type of value some variable refers to.

In contrast, **type inference** tries to figure out the type for that variable *for you*.

The question for the developer is: **when should you explicitly type a variable using type annotation, and when should you rely on type inference**?

## Type Annotations

### Annotating variables

To type annotate a *variable*, just do this:

```ts
// Primitive types
const apples: number = 5;
const hasName: boolean = true;
```

### Annotating objects

To annotate more complex object types, just do this:

```ts
// Class
const date: Date = new Date();
// Array
const colors: string[] = ['red', 'green', 'blue'];
// Object literal (for properties)
const point: { x: number; y: number } = { x: 10, y: 20 };
```

### Annotating functions

To annotate a *function*, just do this:

```ts
const logNumber: (i: number) => void = (i: number) => {
  console.log(i);
};
```

**Note**: `(i: number) => void` is the syntax for type annotating a *variable storing a function*. (You'll learn how to annotate a *function itself* later.) The left-hand side tells TypeScript the types for the arguments, while the right-hand side tells TypeScript the type for the return value.

## Understanding Type Inference

Take the following type annotation:

```ts
let apples: number = 5;
```

What happens if you remove the type annotation?

```ts
let apples = 5;
```

You will find that TypeScript *still* types `apples` as `number`. This is an example of **type inference**.

**Note**: Type inference only works if *variable declaration and initialization* happen on the same line. So, if I do it on a separate line, TypeScript won't automatically infer the type for us:

```ts
let apples;
apples = 5; // `apples` will be of type `any`
```

## When to Use Type Annotations vs. Type Inference

In general, we want to try to use *type inference*. That's because it means less code to write.

However, there are at least 3 situations when you need to use type annotations:

1. When a function returns the `any` type, and we need to clarify the value
2. When you declare a variable on one line and *delay* initialization for another line
3. When you want a variable to have a type that *can't be inferred*

### Functions that returns the `any` type

The `any` type is a type that tells TypeScript that we have no idea what type the variable is.

Some functions that depend on the input to determine the return type will return the `any` type because it can't reasonably predict the return type.

For example, `JSON.parse` could return any number of types depending on the JSON string you input. If you pass "'false'", you get back a boolean. If you pass `'5'`, you get back a number.

However, allowing `JSON.parse` to return the `any` type wastes the potential of TypeScript. If you don't type your variables, you can't get helpful error messages if you do something wrong.

```ts
// infers the `any` type
const age = JSON.parse('25');
// no error message for this fake property
age.notRealProperty;
```

To solve this, we explicitly include a *type annotation*:

```ts
const age: number = JSON.parse('25');
age.notRealProperty; // now TypeScript will complain
```

### Delayed initialization

When you delay initialization, type inference doesn't work, and your variable is assigned the `any` type.

```ts
let target; // `any` type
if (isAvailable) {
  target = 'Ready to use';
} else {
  target = 'Not ready';
}
```

Similar to the function case above, this is bad practice in TypeScript.

To solve this problem, we just apply type annotation.

```ts
let target: string;
if (isAvailable) {
  target = 'Ready to use';
} else {
  target = 'Not ready';
}
```

### When inference doesn't work

Type inference breaks down when the variable's type can be more than one type.

A real-world case of this might be you're storing a user's `favouriteMedia`, and that variable could receive either a `Book` instance, `Movie` instance, or `Song` instance.

To solve this, you can use the `|` operator, which is sort of like an or operator for your types.

Since type inference doesn't support multiple types, you *must* type annotate to use the `|` operator.

```ts
const media = [
  new Book({ rating: 90 }),
  new Movie({ rating: 98 }),
  new Song({ rating: 10 }),
];

let favouriteMedia: Book | Movie | Song;

media.forEach(item => {
  if (item.rating > 95) {
    favouriteMedia = item;
  }
});
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://notes.danfitz.com/javascript/typescript-developers-guide/c-type-annotations-in-action.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
