Simple Moving Average - SMA (Rolling Mean)

Simple Moving Average (Rolling Mean)

The Problem First

Imagine you're tracking your daily steps for a week:

Mon: 3,000 | Tue: 12,000 | Wed: 2,500 | Thu: 11,000 | Fri: 4,000 | Sat: 13,000 | Sun: 3,500

The numbers jump up and down wildly. It's hard to answer: "Am I generally becoming more active or not?"

This is the core problem — raw data is noisy. Moving Average solves this.


What is Moving Average?

Moving Average = Average of the last N values, calculated at every step

Instead of looking at one day's value, you look at the average of the last few days. Then you "move" forward one step and calculate again.


Simple Example — Window Size = 3

Your daily steps:

Day

Steps

3-Day Moving Avg

Mon

3,000

Tue

12,000

Wed

2,500

(3000+12000+2500)/3 = 5,833

Thu

11,000

(12000+2500+11000)/3 = 8,500

Fri

4,000

(2500+11000+4000)/3 = 5,833

Sat

13,000

(11000+4000+13000)/3 = 9,333

Sun

3,500

(4000+13000+3500)/3 = 6,833

 See what happened? The moving average values — 5833 → 8500 → 5833 → 9333 → 6833 — are much smoother than the original jumpy numbers.


Why Do We Use It?

1. To remove noise Raw data has random spikes that don't mean anything. Moving average filters them out so you see the real trend.

2. To see the big picture Instead of asking "did I walk a lot today?", you ask "have I been walking more this week overall?" — much more meaningful.

3. Used everywhere in real life

  • 📈 Stock market — 50-day and 200-day moving averages tell traders the trend direction
  • 🌡️ Weather — "average temperature this month" smooths daily fluctuations
  • 🏪 Sales forecasting — businesses predict next month's sales using past months' averages
  • 🤖 ML / Time Series — it's a classic feature used in models to capture trends

The "Window" Concept

The window size (N) controls how smooth vs. sensitive the average is:

Window Size

Effect

Small (N=2 or 3)

Reacts quickly to changes, still a bit noisy

Large (N=7 or 30)

Very smooth, but slow to react to new changes

Think of it like sunglasses — darker glasses block more light (more smoothing), but you also miss some details.

Where Moving Average is Actually Used (ML/Data Science Context)

1. Time Series Forecasting

When you have data over time — stock prices, sales, temperature, website traffic — raw data is too noisy to feed directly into a model. Moving average smooths it first, making patterns clearer for the model to learn.

2. Feature Engineering

This is the biggest use case for you as an ML engineer.

Before training a model, you create new columns like:

  • price_7day_avg — average price of last 7 days
  • sales_30day_avg — average sales of last 30 days

These features help the model understand "what has been happening recently" — which a single day's value can't tell.

3. Anomaly Detection

If today's value is very far from the moving average, it's probably an anomaly — fraud, system failure, sudden spike. Moving average becomes your baseline to compare against.

4. Signal Smoothing (before EDA or Visualization)

Before you even plot data, applying moving average removes visual noise so you can actually see the trend in your EDA (Exploratory Data Analysis).

5. Stock/Finance Models

Classic use — 50-day MA crossing 200-day MA is a buy/sell signal. If you ever build a finance-related ML model, this will be a standard feature.


Python Program


    import pandas as pd
    import numpy as np
    import matplotlib.pyplot as plt

    # --- Sample Data: Daily Sales for 15 days ---
    data = {
        'day': list(range(1, 16)),
        'sales': [200, 450, 180, 500, 220, 480, 210, 460, 190, 510, 230, 490, 200, 470, 215]
    }

    df = pd.DataFrame(data)

    # --- Calculate Moving Averages ---
    df['SMA_3'] = df['sales'].rolling(window=3).mean()   # 3-day simple moving avg
    df['SMA_7'] = df['sales'].rolling(window=7).mean()   # 7-day simple moving avg
    df['EMA_3'] = df['sales'].ewm(span=3, adjust=False).mean()  # 3-day exponential moving avg

    print(df.to_string(index=False))

    # --- Plot ---
    plt.figure(figsize=(12, 5))
    plt.plot(df['day'], df['sales'],  label='Raw Sales',  marker='o', linewidth=1.5)
    plt.plot(df['day'], df['SMA_3'],  label='SMA (3-day)', linewidth=2)
    plt.plot(df['day'], df['SMA_7'],  label='SMA (7-day)', linewidth=2)
    plt.plot(df['day'], df['EMA_3'],  label='EMA (3-day)', linewidth=2, linestyle='--')

    plt.title('Moving Average on Sales Data')
    plt.xlabel('Day')
    plt.ylabel('Sales')
    plt.legend()
    plt.grid(True)
    plt.tight_layout()
    plt.savefig('moving_average.png')
    plt.show()
    print("Plot saved!")


Output:

day sales SMA_3 SMA_7 EMA_3 1 200 NaN NaN 200.000000 2 450 NaN NaN 325.000000 3 180 276.666667 NaN 252.500000 4 500 376.666667 NaN 376.250000 5 220 300.000000 NaN 298.125000 6 480 400.000000 NaN 389.062500 7 210 303.333333 320.000000 299.531250 8 460 383.333333 357.142857 379.765625 9 190 286.666667 320.000000 284.882812 10 510 386.666667 367.142857 397.441406 11 230 310.000000 328.571429 313.720703 12 490 410.000000 367.142857 401.860352 13 200 306.666667 327.142857 300.930176 14 470 386.666667 364.285714 385.465088 15 215 295.000000 329.285714 300.232544 Plot saved!



What Each Line Does

Code

What it does

rolling(window=3).mean()

SMA — simple average of last 3 values

rolling(window=7).mean()

SMA — wider window, smoother line

ewm(span=3).mean()

EMA — gives more weight to recent values


Output You'll See

  • First 2 rows of SMA_3 will be NaN — that's normal, because you need at least 3 values to start calculating
  • First 6 rows of SMA_7 will be NaN — same reason
  • EMA has no NaN — it starts calculating from day 1

Real ML Usage (Feature Engineering snippet)


    # In a real ML project, you'd add these as features before training
    df['sales_lag1']  = df['sales'].shift(1)         # yesterday's sales
    df['sales_sma3']  = df['sales'].rolling(3).mean() # 3-day avg (trend feature)
    df['sales_sma7']  = df['sales'].rolling(7).mean() # 7-day avg (long trend)
    df['sales_ema3']  = df['sales'].ewm(span=3, adjust=False).mean()

    # Then drop NaN rows before training
    df.dropna(inplace=True)

    # Now df is ready to be fed into your ML model
    X = df[['sales_lag1', 'sales_sma3', 'sales_sma7', 'sales_ema3']]
    y = df['sales']

This is exactly how time series feature engineering is done in real projects — you create these rolling features and feed them to models like XGBoost, LSTM, or Linear Regression.


One Line Summary

Moving Average takes the average of the last N data points and slides that window forward — turning noisy, jumpy data into a smooth trend line.

That's it! Once you get this idea, SMA and EMA (which you've seen before) are just variations on top of this same concept.

Phase 1 — Prerequisites & TypeScript Deep Dive to Learn Angular

Let's be very clear about one thing first.

Most people jump straight into Angular and then struggle. They don't know why things work the way they do. They copy-paste code without understanding it. Then they get stuck on something simple and have no idea how to fix it.

We are NOT doing that.

We are going to build a rock-solid foundation first. By the time you write your first Angular component, you will understand exactly what is happening and why.


Why TypeScript First?

Angular is written 100% in TypeScript. Every file you create will be a .ts file. If you don't understand TypeScript, you will be confused by Angular syntax from line one.

But more importantly — TypeScript teaches you to think like a structured programmer. It forces you to think about what kind of data you're working with before you work with it. This habit alone will make you a significantly better developer.


Setting Up Your Environment

Before writing a single line of code, let's set up your workspace properly.

Step 1 — Install Node.js

Go to nodejs.org and download the LTS version. LTS means Long Term Support — it's the stable version. Don't download the latest/current version, it may have bugs.

After installing, open your terminal and verify:

node --version
npm --version

You should see version numbers. If you do, Node is installed correctly.

Node.js itself is a JavaScript runtime — it lets you run JavaScript outside the browser. But more importantly for us right now, it comes with npm (Node Package Manager), which is how we install Angular and TypeScript.

Step 2 — Install TypeScript

npm install -g typescript

The -g flag means global — install it on your entire computer, not just one project.

Verify:

tsc --version

tsc stands for TypeScript Compiler. It converts your TypeScript code into regular JavaScript that browsers understand.

Step 3 — Install a Code Editor

Use Visual Studio Code. It's free, it's built by Microsoft (the same people who made TypeScript), and it has the best TypeScript support of any editor.

Download from code.visualstudio.com

Essential VS Code Extensions to install:

  • Angular Language Service — gives you intellisense inside Angular HTML templates
  • Prettier — Code Formatter — auto-formats your code
  • ESLint — catches code quality issues
  • Auto Rename Tag — renames closing tags automatically

Step 4 — Create your TypeScript practice folder

mkdir typescript-practice
cd typescript-practice

Create a file called index.ts inside it. This is where we'll practice everything.

To run any TypeScript file:

tsc index.ts        ← this compiles index.ts into index.js
node index.js       ← this runs the compiled file

Or install ts-node to run TypeScript directly without manually compiling:

npm install -g ts-node
ts-node index.ts    ← compile + run in one command

We'll use ts-node throughout this guide because it's faster.

TypeScript — Complete Deep Dive

Chapter 1 — The Type System — Why It Exists and How It Thinks

Before we write any code, let's understand the problem TypeScript is solving.

In JavaScript, you can do this:


    let userId = 5;
    userId = "hello";        // No error. JavaScript is fine with this.
    userId = true;           // Still no error.
    userId = { name: "x" }; // JavaScript doesn't care.

This seems flexible but it's actually dangerous. Imagine you have a function that calculates a discount based on userId. If userId is accidentally a string, your calculation breaks silently. No error. Just wrong results. And you won't know why until a user reports a bug.

TypeScript fixes this by adding a type system. You declare what kind of value a variable holds, and TypeScript makes sure you never accidentally put the wrong kind of value in it.


    let userId: number = 5;
    userId = "hello";   // ERROR: Type 'string' is not assignable to type 'number'

Now the error shows up immediately in your editor — before you even run the code.

This is called static type checking. Static means it happens at compile time (when you write code), not at runtime (when the code runs). Catching bugs at compile time is infinitely better than catching them in production.

Chapter 2 — Primitive Types — The Building Blocks

TypeScript has 7 primitive types. Let's cover all of them deeply.

2.1 — string

Represents any text value.


    let firstName: string = "Rahul";
    let lastName: string = 'Sharma';           // single quotes also work
    let greeting: string = `Hello, ${firstName} ${lastName}!`; // template literals work too

    console.log(greeting); // Hello, Rahul Sharma!

What you CANNOT do:


    let firstName: string = "Rahul";
    firstName = 42;         // ERROR: Type 'number' is not assignable to type 'string'
    firstName = true;       // ERROR: Type 'boolean' is not assignable to type 'string'


2.2 — number

Represents any numeric value — integers, decimals, negative numbers. Unlike some languages (Java, C++), TypeScript doesn't have separate int and float types. Everything is just number.


    let age: number = 25;
    let price: number = 999.99;
    let temperature: number = -5;
    let bigNumber: number = 1_000_000;    // underscores for readability — still valid
    let hex: number = 0xff;               // hexadecimal
    let binary: number = 0b1010;          // binary

    console.log(age, price, temperature);  // 25  999.99  -5


2.3 — boolean

Represents true or false. That's it. Nothing else.


    let isLoggedIn: boolean = true;
    let hasSubscription: boolean = false;
    let isAdmin: boolean = false;

    if (isLoggedIn && hasSubscription) {
        console.log("Show premium content");
    } else if (isLoggedIn && !hasSubscription) {
        console.log("Show free content");
    } else {
        console.log("Please login");
    }


Output:

Show free content

2.4 — null and undefined

These two are different and understanding the difference matters.

undefined = a variable has been declared but not assigned a value yet. null = a variable has been intentionally set to "no value".


    let userAddress: string | null = null;
    // The user exists but hasn't provided their address yet.
    // We're explicitly saying: this field exists but is empty.

    let draftTitle: string | undefined = undefined;
    // This hasn't been set yet at all.

The string | null syntax is called a Union Type. We'll cover this properly in Chapter 6. For now just read it as "this can be a string OR null".


2.5 — any

any is TypeScript's escape hatch. A variable of type any can hold any value, just like regular JavaScript.


    let data: any = 5;
    data = "hello";     // no error
    data = true;        // no error
    data = { x: 1 };   // no error

Use any sparingly. When you use any, you're essentially turning off TypeScript's protection for that variable. It's sometimes necessary (like when working with third-party libraries that don't have TypeScript support), but don't make a habit of it.

If you find yourself writing any everywhere, you're not actually writing TypeScript — you're writing JavaScript with extra steps.


2.6 — unknown

unknown is the safer alternative to any. A variable of type unknown can hold any value, but before you can use it, you have to check what type it actually is.


    let input: unknown = "Hello World";

    // You CANNOT do this:
    // console.log(input.toUpperCase()); // ERROR: Object is of type 'unknown'

    // You MUST check the type first:
    if (typeof input === "string") {
        console.log(input.toUpperCase()); // Now this works: "HELLO WORLD"
    }

Use unknown instead of any when you genuinely don't know the type ahead of time. It's safer because TypeScript forces you to verify the type before using it.


2.7 — never

never represents a value that never occurs. This is used for functions that never return (they always throw an error or run forever).


    function throwError(message: string): never {
        throw new Error(message);
        // This function never returns normally, so return type is 'never'
    }

    function infiniteLoop(): never {
        while (true) {
            // runs forever
        }
    }

You won't use never much as a beginner, but you'll encounter it in error messages sometimes.


Chapter 3 — Type Inference — TypeScript is Smart

Here's something important: you don't always need to write the type explicitly. TypeScript can figure it out on its own.


    let name = "Rahul";         // TypeScript infers: name is string
    let age = 25;               // TypeScript infers: age is number
    let isActive = true;        // TypeScript infers: isActive is boolean

If you hover over these variables in VS Code, it will show you the inferred type.

This means you don't always need to write:


    let name: string = "Rahul";

You can just write:


    let name = "Rahul";

And TypeScript will still give you an error if you try to assign a number to it later.

When should you write the type explicitly?

  • When declaring a variable without assigning a value yet: let result: string;
  • When the inferred type isn't specific enough
  • In function parameters and return types — always be explicit here for clarity

Chapter 4 — Arrays and Tuples

4.1 — Arrays

There are two ways to type an array:


    // Method 1 — using brackets notation (more common)
    let fruits: string[] = ["apple", "mango", "banana"];
    let scores: number[] = [95, 87, 72, 100];
    let flags: boolean[] = [true, false, true];

    // Method 2 — using generic notation
    let fruits2: Array<string> = ["apple", "mango"];
    let scores2: Array<number> = [95, 87];

Both are valid. Use whichever feels more readable to you. Most Angular developers use Method 1.

Working with arrays:


    let products: string[] = ["Laptop", "Phone", "Tablet"];

    // Add to end
    products.push("Keyboard");
    console.log(products); // ["Laptop", "Phone", "Tablet", "Keyboard"]

    // Remove from end
    products.pop();
    console.log(products); // ["Laptop", "Phone", "Tablet"]

    // Find an item
    let index = products.indexOf("Phone");
    console.log(index); // 1

    // Filter items
    let longNames = products.filter(p => p.length > 5);
    console.log(longNames); // ["Laptop", "Tablet"]

    // Map (transform) items
    let upperProducts = products.map(p => p.toUpperCase());
    console.log(upperProducts); // ["LAPTOP", "PHONE", "TABLET"]

    // Find one item
    let found = products.find(p => p === "Phone");
    console.log(found); // "Phone"

    // Check if item exists
    let exists = products.includes("Laptop");
    console.log(exists); // true

These array methods are used CONSTANTLY in Angular. Especially filter, map, and find. Know them deeply.


4.2 — Tuples

Tuples in TypeScript are fixed-length arrays where each position has a specific, known type.

Basic Syntax


    let point: [number, number] = [10, 20];
    let entry: [string, number] = ["Alice", 30];

The order and types are enforced — swapping them causes a compile error.

Why Use Tuples?

Regular arrays are homogeneous (number[], string[]). Tuples let you group different types together with positional meaning, without needing a full object.

Common Use Cases

1. Returning multiple values from a function


    function getMinMax(nums: number[]): [number, number] {
        return [Math.min(...nums), Math.max(...nums)];
    }

    const [min, max] = getMinMax([3, 1, 4, 1, 5]);

2. Key-value pairs


    const pair: [string, number] = ["age", 25];

3. React-style hooks (this is exactly how useState is typed internally)


    function useState<T>(initial: T): [T, (val: T) => void] { ... }

    const [count, setCount] = useState(0);

Optional & Rest Elements


    // Optional element
    let rgb: [number, number, number, number?] = [255, 0, 128]; // alpha is optional

    // Rest elements (variable length tail)
    let log: [string, ...number[]] = ["scores", 90, 85, 78];

Named Tuple Elements (TS 4.0+)

You can label positions for better readability — labels are purely documentary and don't affect behavior:


    type Range = [start: number, end: number];

    function getRange(): Range {
        return [0, 100];
    }

Readonly Tuples

Prevent mutation with readonly:


    const point: readonly [number, number] = [10, 20];
    point[0] = 5; // ❌ Error: Cannot assign to '0' because it is a read-only

Tuples vs Arrays

Array

Tuple

Length

Variable

Fixed

Types

Homogeneous

Heterogeneous

Access

By index

By index

Use when

Same-type list

Small, ordered group

Key Gotcha

TypeScript doesn't enforce tuple length at runtime — it's a compile-time feature only. If you push to a tuple, TypeScript won't always catch it unless you use readonly.


    let pair: [string, number] = ["hello", 1];
    pair.push(999); // TS allows this — be careful!

    console.log(pair); // ["hello", 1, 999]

In short, use tuples when you have a small, ordered, fixed collection of values with different types and positional meaning matters.

Real-world use in Angular — the useState-style approach:


    // HTTP response often comes as [data, error]
    let apiResponse: [any, string | null] = [{ users: [] }, null];


Chapter 5 — Objects and Type Aliases

5.1 — Typing Objects Inline


    let user: { name: string; age: number; email: string } = {
        name: "Priya",
        age: 28,
        email: "priya@gmail.com"
    };

This works but it's messy. If you need this shape in multiple places, you'd have to repeat this big type annotation everywhere. This is where Type Aliases come in.


5.2 — Type Aliases

A type alias creates a reusable name for a type.


    type User = {
        name: string;
        age: number;
        email: string;
    };

    let user1: User = {
        name: "Priya",
        age: 28,
        email: "priya@gmail.com"
    };

    let user2: User = {
        name: "Rahul",
        age: 25,
        email: "rahul@gmail.com"
    };

    // Now you can reuse 'User' anywhere
    function printUser(user: User): void {
        console.log(`${user.name} (${user.age}) — ${user.email}`);
    }

    printUser(user1); // Priya (28) — priya@gmail.com
    printUser(user2); // Rahul (25) — rahul@gmail.com

5.3 — Optional Properties

Sometimes a property may or may not exist. Use ? to mark it as optional.


    type Product = {
        id: number;
        name: string;
        price: number;
        description?: string;    // optional — may or may not exist
        discount?: number;       // optional
    };

    // This is valid even without description and discount
    let laptop: Product = {
        id: 1,
        name: "Laptop",
        price: 55000
    };

    // This is also valid
    let phone: Product = {
        id: 2,
        name: "iPhone",
        price: 80000,
        description: "Latest model with great camera",
        discount: 5000
    };


5.4 — Readonly Properties

Sometimes you want a property that can be set once but never changed.


    type Config = {
        readonly apiUrl: string;
        readonly maxRetries: number;
        timeout: number;          // this one can change
    };

    let appConfig: Config = {
        apiUrl: "https://api.myapp.com",
        maxRetries: 3,
        timeout: 5000
    };

    appConfig.timeout = 10000;         // OK — timeout is not readonly
    appConfig.apiUrl = "http://other"; // ERROR: Cannot assign to 'apiUrl' because it is a read-only property


Chapter 6 — Interfaces — The Angular Developer's Best Friend

Interfaces are similar to Type Aliases but they work differently under the hood and are more powerful for object shapes.

Here's the key practical difference:

  • Type Aliases can describe any type: objects, unions, primitives, tuples
  • Interfaces are specifically for describing the shape of objects (and classes)

In Angular codebases, you'll see both. But interfaces are more common for defining data shapes that come from APIs.


6.1 — Basic Interface


    interface Product {
        id: number;
        title: string;
        price: number;
        category: string;
        inStock: boolean;
        image?: string;        // optional
    }

    let product1: Product = {
        id: 1,
        title: "MacBook Pro",
        price: 150000,
        category: "Electronics",
        inStock: true
    };

    let product2: Product = {
        id: 2,
        title: "iPhone 15",
        price: 80000,
        category: "Electronics",
        inStock: false,
        image: "iphone15.jpg"
    };


6.2 — Interface with Methods

An interface can also define methods that any implementing object must have.


    interface Vehicle {
        brand: string;
        speed: number;
        accelerate(amount: number): void;
        brake(amount: number): void;
        getInfo(): string;
    }


6.3 — Interface Extending Another Interface

This is where interfaces shine over type aliases — clean inheritance.


    interface Animal {
        name: string;
        age: number;
    }

    interface Dog extends Animal {
        breed: string;
        canFetch: boolean;
    }

    // Dog now has: name, age, breed, canFetch
    let myDog: Dog = {
        name: "Bruno",
        age: 3,
        breed: "Labrador",
        canFetch: true
    };

Real-world Angular example:


    interface BaseEntity {
        id: number;
        createdAt: string;
        updatedAt: string;
    }

    interface User extends BaseEntity {
        name: string;
        email: string;
        role: "admin" | "user" | "guest";
    }

    interface BlogPost extends BaseEntity {
        title: string;
        content: string;
        authorId: number;
        tags: string[];
    }

Now User and BlogPost both automatically have id, createdAt, and updatedAt because they extend BaseEntity. This is exactly the pattern you'll use when your API returns data.


6.4 — Interface vs Type — When to Use Which

For objects that represent data models (API responses, database entities): use Interface


    interface UserResponse {
        id: number;
        name: string;
        email: string;
    }

For unions, tuples, or complex type combinations: use Type


    type Status = "loading" | "success" | "error";
    type ID = string | number;
    type Pair = [string, number];


Chapter 7 — Union and Intersection Types

7.1 — Union Types — OR

A union type means a value can be one type OR another type.


    type StringOrNumber = string | number;

    let id: StringOrNumber = 5;
    id = "abc-123";      // also valid
    id = true;           // ERROR: boolean is not in the union

    // Practical example
    type Status = "active" | "inactive" | "banned";
    let userStatus: Status = "active";
    userStatus = "inactive";  // valid
    userStatus = "deleted";   // ERROR: "deleted" is not in the union

The "active" | "inactive" | "banned" is called a String Literal Union. This is extremely common in Angular. You're not just saying "any string" — you're saying "exactly one of these specific strings".


    // Without union — accepts ANY string
    function setStatus(status: string) { ... }
    setStatus("anything goes");   // no error even if wrong

    // With union — only specific strings allowed
    function setStatus(status: "active" | "inactive" | "banned") { ... }
    setStatus("active");    // valid
    setStatus("deleted");   // ERROR caught at compile time


7.2 — Intersection Types — AND

An intersection type combines multiple types into one. The result must have ALL properties of all combined types.


    type Timestamps = {
        createdAt: string;
        updatedAt: string;
    };

    type UserData = {
        id: number;
        name: string;
        email: string;
    };

    // UserWithTimestamps has ALL properties from both
    type UserWithTimestamps = UserData & Timestamps;

    let user: UserWithTimestamps = {
        id: 1,
        name: "Rahul",
        email: "rahul@gmail.com",
        createdAt: "2024-01-01",
        updatedAt: "2024-03-15"
    };


Chapter 8 — Functions — Deep Dive

Functions are where you'll spend most of your time in Angular. Let's cover everything.

8.1 — Function Parameters and Return Types


    // Basic function with typed params and return type
    function add(a: number, b: number): number {
        return a + b;
    }

    // Arrow function version
    const multiply = (a: number, b: number): number => a * b;

    // Function that returns nothing
    function logError(message: string): void {
        console.error(`[ERROR]: ${message}`);
    }

    // Function with optional parameter
    function greet(name: string, title?: string): string {
        if (title) {
            return `Hello, ${title} ${name}!`;
        }
        return `Hello, ${name}!`;
    }

    console.log(greet("Sharma"));             // Hello, Sharma!
    console.log(greet("Sharma", "Dr."));     // Hello, Dr. Sharma!


8.2 — Default Parameters


    function createUser(
        name: string,
        role: string = "user",        // default value
        isActive: boolean = true      // default value
    ): void {
        console.log(`Created: ${name}, Role: ${role}, Active: ${isActive}`);
    }

    createUser("Rahul");                     // Created: Rahul, Role: user, Active: true
    createUser("Priya", "admin");           // Created: Priya, Role: admin, Active: true
    createUser("Amit", "user", false);      // Created: Amit, Role: user, Active: false


8.3 — Rest Parameters

When you don't know how many arguments will be passed:


    function sum(...numbers: number[]): number {
        return numbers.reduce((total, n) => total + n, 0);
    }

    console.log(sum(1, 2, 3));             // 6
    console.log(sum(10, 20, 30, 40, 50)); // 150


8.4 — Function Types — Functions as Values

In Angular, you'll sometimes pass functions as arguments (callbacks, event handlers). You can type these too.


    // Define a type for a function
    type MathOperation = (a: number, b: number) => number;

    // Use that type
    let add: MathOperation = (a, b) => a + b;
    let subtract: MathOperation = (a, b) => a - b;
    let multiply: MathOperation = (a, b) => a * b;

    function calculate(a: number, b: number, operation: MathOperation): number {
        return operation(a, b);
    }

    console.log(calculate(10, 5, add));       // 15
    console.log(calculate(10, 5, subtract));  // 5
    console.log(calculate(10, 5, multiply));  // 50


8.5 — Async Functions

You'll use these constantly when fetching API data in Angular services.


    // A function that returns a Promise of a number
    async function fetchUserId(name: string): Promise<number> {
        // Simulating an API call delay
        await new Promise(resolve => setTimeout(resolve, 1000));
        return 42; // returning a user ID
    }

    // Calling it
    async function main() {
        const userId = await fetchUserId("Rahul");
        console.log("User ID:", userId); // User ID: 42
    }

    main();


Chapter 9 — Classes — The Heart of Angular

Every single Angular component, service, module, pipe, and guard is a class. Understanding TypeScript classes deeply means understanding Angular deeply.

9.1 — Basic Class Structure


    class BankAccount {
        // Properties
        accountNumber: string;
        holderName: string;
        balance: number;

        // Constructor — runs when you create a new instance
        constructor(accountNumber: string, holderName: string, initialBalance: number) {
            this.accountNumber = accountNumber;
            this.holderName = holderName;
            this.balance = initialBalance;
        }

        // Methods
        deposit(amount: number): void {
            if (amount <= 0) {
                console.log("Deposit amount must be positive");
                return;
            }
            this.balance += amount;
            console.log(`Deposited ₹${amount}. New balance: ₹${this.balance}`);
        }

        withdraw(amount: number): void {
            if (amount > this.balance) {
                console.log("Insufficient funds");
                return;
            }
            this.balance -= amount;
            console.log(`Withdrew ₹${amount}. New balance: ₹${this.balance}`);
        }

        getStatement(): string {
            return `Account: ${this.accountNumber} | Holder: ${this.holderName} | Balance: ₹${this.balance}`;
        }
    }

    // Create instances
    let account1 = new BankAccount("ACC001", "Rahul Sharma", 10000);
    let account2 = new BankAccount("ACC002", "Priya Patel", 25000);

    account1.deposit(5000);    // Deposited ₹5000. New balance: ₹15000
    account1.withdraw(2000);   // Withdrew ₹2000. New balance: ₹13000
    console.log(account1.getStatement());
    // Account: ACC001 | Holder: Rahul Sharma | Balance: ₹13000


9.2 — Access Modifiers — public, private, protected

This is critical for Angular because you'll use access modifiers in every component and service.


    class Employee {
        public name: string;           // accessible from anywhere
        public department: string;

        private salary: number;        // only accessible inside this class
        private ssn: string;           // sensitive data — keep private

        protected employeeId: string;  // accessible here and in subclasses

        constructor(
            name: string,
            department: string,
            salary: number,
            ssn: string,
            employeeId: string
        ) {
            this.name = name;
            this.department = department;
            this.salary = salary;
            this.ssn = ssn;
            this.employeeId = employeeId;
        }

        // A public method that safely exposes salary info
        getSalaryInfo(): string {
            return `${this.name} earns in the ${this.getSalaryRange()} range`;
        }

        // A private helper method — only used internally
        private getSalaryRange(): string {
            if (this.salary < 30000) return "junior";
            if (this.salary < 70000) return "mid-level";
            return "senior";
        }
    }

    let emp = new Employee("Amit", "Engineering", 65000, "XXX-XX-1234", "EMP001");
    console.log(emp.name);           // "Amit" — works, public
    console.log(emp.getSalaryInfo()); // works, public method
    console.log(emp.salary);         // ERROR: 'salary' is private


9.3 — Shorthand Constructor (Used Constantly in Angular)

TypeScript gives you a shorthand to declare and initialize properties directly in the constructor:


    // Long way:
    class User {
        name: string;
        email: string;
        role: string;

        constructor(name: string, email: string, role: string) {
            this.name = name;
            this.email = email;
            this.role = role;
        }
    }

    // Shorthand way (EXACT same result):
    class User {
        constructor(
            public name: string,
            public email: string,
            private role: string
        ) { }   // constructor body is empty — TypeScript handles it automatically
    }

You will see this shorthand in Angular services ALL the time:


    // Angular service injection shorthand
    constructor(
        private http: HttpClient,
        private router: Router,
        private authService: AuthService
    ) { }

That one line declares http, router, and authService as private properties AND injects them. This is the standard Angular pattern.


9.4 — Inheritance — extends


    class Animal {
        name: string;
        sound: string;

        constructor(name: string, sound: string) {
            this.name = name;
            this.sound = sound;
        }

        makeSound(): void {
            console.log(`${this.name} says ${this.sound}`);
        }

        describe(): string {
            return `I am ${this.name}`;
        }
    }

    class Dog extends Animal {
        breed: string;

        constructor(name: string, breed: string) {
            super(name, "Woof");   // super() calls the parent constructor
            this.breed = breed;
        }

        fetch(item: string): void {
            console.log(`${this.name} fetched the ${item}!`);
        }

        // Override parent method
        describe(): string {
            return `${super.describe()} and I am a ${this.breed}`;
        }
    }

    let dog = new Dog("Bruno", "Labrador");
    dog.makeSound();          // Bruno says Woof
    dog.fetch("ball");        // Bruno fetched the ball!
    console.log(dog.describe()); // I am Bruno and I am a Labrador


9.5 — Abstract Classes

An abstract class is a class that cannot be instantiated directly. It serves as a template for other classes.


    abstract class Shape {
        color: string;

        constructor(color: string) {
            this.color = color;
        }

        // Abstract method — subclasses MUST implement this
        abstract calculateArea(): number;

        // Regular method — subclasses inherit this as-is
        describe(): void {
            console.log(`This is a ${this.color} shape with area ${this.calculateArea()}`);
        }
    }

    class Circle extends Shape {
        radius: number;

        constructor(color: string, radius: number) {
            super(color);
            this.radius = radius;
        }

        calculateArea(): number {   // must implement abstract method
            return Math.PI * this.radius * this.radius;
        }
    }

    class Rectangle extends Shape {
        width: number;
        height: number;

        constructor(color: string, width: number, height: number) {
            super(color);
            this.width = width;
            this.height = height;
        }

        calculateArea(): number {   // must implement abstract method
            return this.width * this.height;
        }
    }

    let circle = new Circle("red", 5);
    circle.describe();  // This is a red shape with area 78.53...

    let rect = new Rectangle("blue", 10, 4);
    rect.describe();    // This is a blue shape with area 40

    // let shape = new Shape("green");  // ERROR: Cannot instantiate abstract class


Chapter 10 — Generics — Writing Flexible Reusable Code

Generics are one of the most powerful TypeScript features and they appear everywhere in Angular, especially with HTTP calls and RxJS.

10.1 — The Problem Generics Solve

Imagine you want to write a function that returns the first item of an array. Without generics:


    function getFirstItem(arr: string[]): string {
        return arr[0];
    }
    // Only works for string arrays. What about number arrays? object arrays?

You'd have to write the same function multiple times for each type. OR use any, which loses type safety.

With Generics:


    function getFirstItem<T>(arr: T[]): T {
        return arr[0];
    }

    // TypeScript infers the type automatically
    let firstFruit = getFirstItem(["apple", "mango", "banana"]);
    // TypeScript knows firstFruit is a string

    let firstScore = getFirstItem([95, 87, 72]);
    // TypeScript knows firstScore is a number

    let firstUser = getFirstItem([{ id: 1, name: "Rahul" }, { id: 2, name: "Priya" }]);
    // TypeScript knows firstUser is { id: number, name: string }

<T> is a type parameter. It's a placeholder for whatever type gets passed in. The name T is convention (stands for Type), but you can use any name.


10.2 — Generic Interfaces — The Angular HTTP Pattern

This is exactly how Angular's HTTP client works:


    // Generic API response wrapper
    interface ApiResponse<T> {
        data: T;
        status: number;
        message: string;
        timestamp: string;
    }

    // Specific interfaces for different data
    interface User {
        id: number;
        name: string;
        email: string;
    }

    interface Product {
        id: number;
        title: string;
        price: number;
    }

    // Now use the generic wrapper with specific types
    let userResponse: ApiResponse<User> = {
        data: { id: 1, name: "Rahul", email: "rahul@gmail.com" },
        status: 200,
        message: "Success",
        timestamp: "2024-03-28T10:00:00Z"
    };

    let productResponse: ApiResponse<Product> = {
        data: { id: 1, title: "Laptop", price: 55000 },
        status: 200,
        message: "Success",
        timestamp: "2024-03-28T10:00:00Z"
    };

    // ApiResponse<User[]> for a list of users
    let usersResponse: ApiResponse<User[]> = {
        data: [
            { id: 1, name: "Rahul", email: "rahul@gmail.com" },
            { id: 2, name: "Priya", email: "priya@gmail.com" }
        ],
        status: 200,
        message: "Success",
        timestamp: "2024-03-28T10:00:00Z"
    };

In Angular's HTTP client, you write this.http.get<User[]>(url). That <User[]> is a generic — you're telling TypeScript what shape the API response data will be.


10.3 — Generic Classes


    class Stack<T> {
        private items: T[] = [];

        push(item: T): void {
            this.items.push(item);
        }

        pop(): T | undefined {
            return this.items.pop();
        }

        peek(): T | undefined {
            return this.items[this.items.length - 1];
        }

        isEmpty(): boolean {
            return this.items.length === 0;
        }

        size(): number {
            return this.items.length;
        }
    }

    // A stack of numbers
    let numberStack = new Stack<number>();
    numberStack.push(10);
    numberStack.push(20);
    numberStack.push(30);
    console.log(numberStack.peek());  // 30
    console.log(numberStack.pop());   // 30
    console.log(numberStack.size());  // 2

    // A stack of strings — same class, different type
    let stringStack = new Stack<string>();
    stringStack.push("first");
    stringStack.push("second");
    console.log(stringStack.pop());   // "second"


Chapter 11 — Enums — Named Constants

Enums let you define a set of named constants. Instead of using magic strings or numbers throughout your code, you give them meaningful names.


    // Without enum — bad practice
    let userRole = "admin";      // What are the valid values? Hard to know.
    let orderStatus = 2;         // What does 2 mean? Hard to know.

    // With enum — clear and safe
    enum UserRole {
        Admin = "admin",
        User = "user",
        Guest = "guest",
        Moderator = "moderator"
    }

    enum OrderStatus {
        Pending = "PENDING",
        Processing = "PROCESSING",
        Shipped = "SHIPPED",
        Delivered = "DELIVERED",
        Cancelled = "CANCELLED"
    }

    // Using enums
    let currentUserRole: UserRole = UserRole.Admin;
    let currentOrderStatus: OrderStatus = OrderStatus.Processing;

    console.log(currentUserRole);   // "admin"
    console.log(currentOrderStatus); // "PROCESSING"

    // Excellent for switch statements
    function getStatusMessage(status: OrderStatus): string {
        switch (status) {
            case OrderStatus.Pending:
                return "Your order is waiting to be processed";
            case OrderStatus.Processing:
                return "Your order is being prepared";
            case OrderStatus.Shipped:
                return "Your order is on its way";
            case OrderStatus.Delivered:
                return "Your order has been delivered";
            case OrderStatus.Cancelled:
                return "Your order has been cancelled";
            default:
                return "Unknown status";
        }
    }

    console.log(getStatusMessage(OrderStatus.Shipped));
    // "Your order is on its way"


Chapter 12 — Type Guards and Narrowing

Type narrowing is the process of refining a type within a conditional block. TypeScript is smart enough to understand that after a type check, the type is more specific.


    type StringOrNumber = string | number;

    function processValue(value: StringOrNumber): string {
        // At this point, 'value' could be string or number

        if (typeof value === "string") {
            // Inside here, TypeScript KNOWS value is a string
            return value.toUpperCase();  // .toUpperCase() is valid
        } else {
            // Inside here, TypeScript KNOWS value is a number
            return value.toFixed(2);     // .toFixed() is valid
        }
    }

    console.log(processValue("hello"));  // "HELLO"
    console.log(processValue(42.567));   // "42.57"

With interfaces:


    interface Cat {
        name: string;
        meow(): void;
    }

    interface Dog {
        name: string;
        bark(): void;
    }

    type Pet = Cat | Dog;

    // Type guard function
    function isCat(pet: Pet): pet is Cat {
        return "meow" in pet;
    }

    function makeNoise(pet: Pet): void {
        if (isCat(pet)) {
            pet.meow();   // TypeScript knows it's a Cat here
        } else {
            pet.bark();   // TypeScript knows it's a Dog here
        }
    }


Chapter 13 — Decorators (Angular's Secret Sauce)

Decorators are a special TypeScript feature that Angular uses for absolutely everything. Let's understand them deeply.

A decorator is a function that is applied to a class, method, property, or parameter using the @ symbol. It adds metadata or modifies behavior.


13.1 — Class Decorator


    // This is a decorator factory — a function that returns a decorator
    function Component(config: { selector: string; template: string }) {
        return function (constructor: Function) {
            // Attach metadata to the class
            constructor.prototype.selector = config.selector;
            constructor.prototype.template = config.template;
            console.log(`Component registered: ${config.selector}`);
        }
    }

    // Using the decorator
    @Component({
        selector: 'app-header',
        template: '<header>My App</header>'
    })
    class HeaderComponent {
        // class code
    }
    // Console: "Component registered: app-header"

This is literally what Angular's @Component() decorator does — it takes your class and registers it as an Angular component with the selector and template metadata.


13.2 — Property Decorator


    function Log(target: any, propertyKey: string) {
        let value = target[propertyKey];

        Object.defineProperty(target, propertyKey, {
            get: () => {
                console.log(`Getting ${propertyKey}: ${value}`);
                return value;
            },
            set: (newValue) => {
                console.log(`Setting ${propertyKey} to: ${newValue}`);
                value = newValue;
            }
        });
    }

    class User {
        @Log
        name: string = "Rahul";
    }

    let user = new User();
    user.name = "Priya";   // Console: "Setting name to: Priya"
    console.log(user.name); // Console: "Getting name: Priya"

Angular's @Input() and @Output() work on this same principle — they're property decorators.


Chapter 14 — Modules and Imports/Exports

This is fundamental to how Angular is organized. Every Angular project is a set of TypeScript modules importing and exporting things from each other.


    // math-utils.ts
    export function add(a: number, b: number): number {
        return a + b;
    }

    export function subtract(a: number, b: number): number {
        return a - b;
    }

    export const PI = 3.14159265;

    // Default export — only one per file
    export default function multiply(a: number, b: number): number {
        return a * b;
    }


    // main.ts
    import multiply, { add, subtract, PI } from './math-utils';
    // multiply is the default export, add/subtract/PI are named exports

    console.log(add(5, 3));          // 8
    console.log(subtract(10, 4));    // 6
    console.log(PI);                 // 3.14159265
    console.log(multiply(3, 4));     // 12


    // Import everything as a namespace
    import * as MathUtils from './math-utils';
    console.log(MathUtils.add(2, 2));  // 4

In Angular, every component, service, module, and interface is exported from its file and imported where needed. This module system is how Angular organizes code.


Phase 1 Complete — You're TypeScript Ready


Let's recap everything we covered:

Type System — Why TypeScript exists, static type checking, catching bugs before runtime

Primitive Types — string, number, boolean, null, undefined, any, unknown, never — all 7 with real use cases

Type Inference — TypeScript figuring out types automatically

Arrays and Tuples — Typed arrays, array methods (map, filter, find, reduce), fixed-length tuples

Objects and Type Aliases — Inline object types, reusable type aliases, optional and readonly properties

Interfaces — Object blueprints, extending interfaces, interface vs type

Union and Intersection Types — OR types, AND types, string literal unions

Functions — Parameters, return types, optional params, default params, rest params, function types, async functions

Classes — Properties, constructors, methods, access modifiers (public/private/protected), shorthand constructors, inheritance with extends, super(), abstract classes

Generics — Generic functions, generic interfaces, generic classes — the foundation for Angular's HTTP calls

Enums — Named constants for roles, statuses, and categories

Type Guards — Narrowing types inside conditionals, custom type guard functions

Decorators — Class, property, and method decorators — exactly how Angular uses them

Modules — Export, import, default exports, named exports


One Final Practice Exercise Before Angular

Write this from scratch to test your understanding:

Build a simple Library system:

  1. Create an interface Book with id, title, author, year, genre, and optional rating
  2. Create an enum Genre with at least 5 genres
  3. Create a class Library with a private array of books
  4. Add methods: addBook, removeBook, findByAuthor, findByGenre, getTopRated
  5. The getTopRated method should accept a minimum rating and return all books above it
  6. Use proper TypeScript types everywhere — no any

If you can build this comfortably, you are ready for Angular Phase 2.

Mean — Complete Chapter for ML & Statistics

What is Mean? We calculate the mean (average) because it gives a single value that represents the whole dataset. Why we need mean (benefits...