📖 The Story: The Undefined Disaster

A frontend developer was building a user profile page. The API returned a user object. The developer wrote const displayName = user.name.toUpperCase(). It worked perfectly in their local environment.

In production, a new user signed up via OAuth (Google) and hadn't set a name yet. The API returned name: null. The frontend called null.toUpperCase(), the app crashed instantly, and the user saw a white screen.

If the backend team had used TypeScript, the API contract would have defined name: string | null. The frontend TypeScript compiler would have immediately flagged user.name.toUpperCase() as a potential crash, forcing the developer to handle the null case.

Types aren't just about IDE autocomplete; they are about enforcing contracts between systems.

🎯 Why Annotations?

📝

Contracts

Define exactly what a function or variable expects and returns.

🛡️

Safety

Prevent null/undefined crashes and type mismatches before runtime.

📖

Readability

Types serve as live documentation for the next developer.

🧒 Explain Like I'm 10

Imagine you are packing boxes for a move. You have a box labeled "Books" and a box labeled "Glasses".

If you try to put a heavy book in the "Glasses" box, your mom stops you. "No! Books go in the Book box!" She is the TypeScript compiler.

Type annotations are the labels on the boxes. They tell the compiler exactly what is allowed inside.

🎓 Professional Explanation

TypeScript types are erased at runtime. They exist purely to help the compiler catch errors during development. The most common types are the JavaScript primitives: string, number, and boolean.

📦 Primitives

typescript
let username: string = "Ram";
let age: number = 30;
let isActive: boolean = true;

// Type Inference: You don't always need to write the type!
// TypeScript infers 'role' is a string automatically.
let role = "Admin"; 

📚 Arrays & Tuples

Arrays are written with [] after the type. Tuples are fixed-length arrays where the types at each index are known.

typescript
// Array of numbers
let scores: number[] = [90, 85, 100];

// Tuple: fixed length and types
// 1st element is a number, 2nd is a string
let userRecord: [number, string] = [1, "Ram"];

⚠️ Any vs Unknown

This is the most critical concept in TypeScript. any turns off the compiler. unknown forces you to check the type before using it.

typescript · Bad (any)
let data: any = fetchData();

// Compiler allows anything. Will crash at runtime if data is null.
console.log(data.user.name.toUpperCase()); 
typescript · Good (unknown)
let data: unknown = fetchData();

// Error: Object is of type 'unknown'.
console.log(data.user.name.toUpperCase()); 

// You MUST narrow the type first!
if (typeof data === 'object' && data !== null) {
  // Safe to use...
}

Rule of thumb: If you don't know the type, use unknown. It is the type-safe counterpart to any.

⚠️ Common Mistakes

Mistake 1: Over-annotating

typescript · Bad
// Bad: Redundant. TS already knows it's a string.
let name: string = "Ram"; 

// Good: Let inference do the work for variables.
let name = "Ram";

✅ Best Practices

  1. Use Type Inference for variables: Only annotate function parameters and return types explicitly.
  2. Avoid any: Use unknown if the type is truly dynamic.
  3. Enable noImplicitAny: In tsconfig.json, ensure this is true so the compiler warns you about implicit any types.

🏗️ Senior Deep Dive

Structural Typing vs Nominal Typing

TypeScript uses Structural Typing (Duck Typing). If it walks like a duck and quacks like a duck, it's a duck. Two objects with the same shape are compatible, even if they have different names. This is different from languages like Java or C# which use Nominal Typing (identity matters).

💼 Interview Questions

Beginner
What is Type Inference?
Show Answer
It is the compiler's ability to automatically deduce the type of a variable based on its initial value, reducing the need for explicit type annotations.
Intermediate
Explain the difference between any and unknown.
Show Answer
any disables type checking, allowing any operation without errors. unknown is a type-safe version; you cannot perform operations on it until you verify its structure using type guards.

🏋️ Practical Exercise

🎯 Hands-On Practice Easy

Fix the Types

Fix the TypeScript errors in this code snippet without using any.

typescript">
let userAge = "25";
userAge + 5; // We want this to equal 30, not "255"

Task: Change the declaration of userAge so the math works correctly.

📝 Quiz

Test your understanding. Click an option to check your answer.

1. Which type should you use if you don't know the shape of the data at compile time?
A) any
B) unknown
C) string
Answer: B — unknown forces you to check the type before using it, whereas any disables all safety.

📦 Summary

🎯 Key Takeaways

  • Basic types include string, number, boolean, array, and tuple.
  • TypeScript can infer types, but explicit annotations are great for function contracts.
  • Avoid any; use unknown for dynamic data.
  • TypeScript uses structural typing (shape matters, not name).