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:
// Primitive types
const apples: number = 5;
const hasName: boolean = true;Annotating objects
To annotate more complex object types, just do this:
// 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:
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:
let apples: number = 5;What happens if you remove the type annotation?
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:
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:
When a function returns the
anytype, and we need to clarify the valueWhen you declare a variable on one line and delay initialization for another line
When you want a variable to have a type that can't be inferred
Functions that returns the any type
any typeThe 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.
// 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:
const age: number = JSON.parse('25');
age.notRealProperty; // now TypeScript will complainDelayed initialization
When you delay initialization, type inference doesn't work, and your variable is assigned the any type.
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.
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.
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;
}
});Last updated