- TypeScript Tutorial
- TypeScript Home
- TypeScript Introduction
- TypeScript Setup
- TypeScript First Program
- TypeScript vs JavaScript
- TypeScript Data Types
- TypeScript Type Inference
- TypeScript Type Annotations
- TypeScript Interfaces
- TypeScript Enums
- TypeScript Type Aliases
- TypeScript Type Assertions
- TypeScript Variables
- TypeScript Functions
- TypeScript Functions
- TypeScript Optional Parameters
- TypeScript Default Parameters
- TypeScript Rest Parameters
- TypeScript Arrow Functions
- Classes and Objects
- Introduction to Classes
- Properties and Methods
- Access Modifiers
- Static Members
- Inheritance
- Abstract Classes
- Interfaces vs Classes
- Advanced Types
- TypeScript Union Types
- TypeScript Intersection Types
- TypeScript Literal Types
- TypeScript Nullable Types
- TypeScript Type Guards
- TypeScript Discriminated Unions
- TypeScript Index Signatures
- TypeScript Generics
- Introduction to Generics
- TypeScript Generic Functions
- TypeScript Generic Classes
- TypeScript Generic Constraints
- TypeScript Modules
- Introduction to Modules
- TypeScript Import and Export
- TypeScript Default Exports
- TypeScript Namespace
- Decorators
- Introduction to Decorators
- TypeScript Class Decorators
- TypeScript Method Decorators
- TypeScript Property Decorators
- TypeScript Parameter Decorators
- Configuration
- TypeScript tsconfig.json File
- TypeScript Compiler Options
- TypeScript Strict Mode
- TypeScript Watch Mode
TypeScript Type Annotations
Type annotations are the heart and soul of TypeScript. They allow developers to explicitly specify what kind of data a variable, function parameter, or return value should hold. While vanilla JavaScript is "dynamically typed" (meaning variables can change types on the fly), TypeScript uses these annotations to enforce "static typing." This ensures that if you declare a variable as a number, it stays a number, preventing a whole category of common runtime bugs before you even hit save.
Why Use Type Annotations?
- Catch Errors Early: Identify type mismatches during development rather than discovering them through crashes in production.
- Enhanced IDE Support: Annotations enable powerful "Intellisense," providing accurate autocomplete and real-time documentation as you type.
- Self-Documenting Code: When you look at a function six months later, annotations tell you exactly what inputs it expects without needing to hunt through the logic.
- Refactoring Confidence: Changing a data structure becomes much safer because TypeScript will highlight every single place in your app that needs to be updated.
Variable Type Annotations
To annotate a variable, use a colon (:) after the variable name, followed by the type (e.g., string, number, boolean).
let age: number = 25;
let name: string = "TypeScript";
let isValid: boolean = true;
console.log(age, name, isValid);
If you attempt to assign a value that doesn't match the annotated type, the TypeScript compiler will flag it immediately with a descriptive error.
let count: number = 10;
count = "Hello"; // Error: Type 'string' is not assignable to type 'number'
let x = 5), TypeScript is smart enough to "infer" the type as number. Use explicit annotations when the type isn't obvious or when you are declaring a variable without an immediate value.
Function Type Annotations
Functions are where logic lives, and they are the most common source of bugs. By annotating parameters and return values, you ensure the function is used correctly throughout your codebase.
function add(a: number, b: number): number {
return a + b;
}
let sum = add(10, 20);
console.log(sum); // Output: 30
If a function is designed to perform an action (like logging to a console or saving to a database) rather than returning a value, we use the void type.
function logMessage(message: string): void {
console.log(message);
// No return statement here
}
logMessage("Hello, TypeScript!");
any, which effectively turns off type checking for that function.
Array Type Annotations
When working with lists, you want to ensure every element in the list follows the same rules. You can annotate arrays using the syntax type[].
let numbers: number[] = [1, 2, 3, 4];
let names: string[] = ["Alice", "Bob", "Charlie"];
// Real-world example: A list of active product IDs
let activeOrders: number[] = [1021, 1022, 1025];
numbers.push(5); // Valid
names.push("David"); // Valid
// Invalid assignment
numbers.push("Hello"); // Error: Argument of type 'string' is not assignable to parameter of type 'number'
Array<number>. Both are valid, but number[] is generally preferred by the community for its brevity and readability.
Object Type Annotations
Objects in JavaScript can be complex. In TypeScript, you define the "shape" of the object by specifying the type of each property it must contain.
let person: {
name: string;
age: number;
isStudent: boolean;
} = {
name: "John",
age: 25,
isStudent: true
};
console.log(person.name, person.age);
Union Type Annotations
Sometimes a variable needs to be flexible. For example, a User ID might be a numeric 101 from an old database or a UUID "a1-b2" from a new one. Union types allow a variable to hold one of several specified types using the pipe (|) symbol.
let id: string | number;
id = "123"; // Valid
id = 123; // Valid
// Real-world example: Handling a search status
let status: "loading" | "success" | "error";
status = "loading"; // Valid
status = "finished"; // Error: Type '"finished"' is not assignable to status
Type Annotations with any
The any type is a "escape hatch" that tells TypeScript to skip type checking for a specific variable. While it might seem convenient, it removes the benefits of using TypeScript in the first place.
let randomValue: any = 10;
randomValue = "Hello";
randomValue = true;
console.log(randomValue); // Output: true
any is a slippery slope toward "Type-less Script." Use it sparingly, perhaps when migrating a legacy JavaScript project or when dealing with third-party data where the structure is genuinely unknown.
Optional Parameters
In real-world applications, not every piece of data is mandatory. You can mark function parameters or object properties as optional by adding a question mark (?) before the colon.
function greet(name: string, age?: number): void {
console.log(`Hello, ${name}`);
if (age !== undefined) {
console.log(`You are ${age} years old.`);
}
}
greet("John"); // Valid: age is undefined
greet("Alice", 30); // Valid: age is 30
Summary
Type annotations in TypeScript provide a robust way to define the data structures in your application. By being explicit about variables, function signatures, and objects, you create a codebase that is easier to debug, document, and scale. While it may feel like more typing (literally!) at first, the time saved by catching bugs early far outweighs the initial effort.