Q: What are Type Guards in TypeScript?

Answer:

A Type Guard is a technique in TypeScript that allows you to narrow down the type of a variable within a conditional block. By performing a runtime check, you give TypeScript the guarantee it needs to let you safely access properties that belong only to a specific type.

TypeScript supports several built-in type guards, and also allows you to define your own.

1. typeof

Used to check basic, standard Javascript primitive types (string, number, boolean, symbol).

function printId(id: number | string) {
    if (typeof id === "string") {
        // In this block, TypeScript knows `id` is a string
        console.log(id.toUpperCase());
    } else {
        // Here, TypeScript knows it's a number
        console.log(id.toFixed(2));
    }
}

2. instanceof

Used to check if an object was constructed from a specific class.

class Car { drive() {} }
class Plane { fly() {} }

function moveVehicle(vehicle: Car | Plane) {
    if (vehicle instanceof Car) {
        vehicle.drive(); 
    } else {
        vehicle.fly(); 
    }
}

3. The in Operator

Often used to narrow down structural types (like interfaces or generic objects) by checking if a specific property exists on the object.

interface Bird { fly(): void; }
interface Fish { swim(): void; }

function moveAnimal(animal: Bird | Fish) {
    if ("fly" in animal) {
        animal.fly(); // TypeScript narrowed `animal` down to `Bird`
    } else {
        animal.swim(); // Narrowed to `Fish`
    }
}

4. User-Defined Type Guards (Type Predicates)

Sometimes standard checks aren't descriptive enough. You can define a custom validation function that returns a type predicate (parameterName is Type).

interface Admin { role: string; privileges: string[]; }
interface User { role: string; lastLogin: Date; }

// The `person is Admin` tells the TS compiler the type if this returns true
function isAdmin(person: Admin | User): person is Admin {
    // We are doing a manual check
    return (person as Admin).privileges !== undefined;
}

function processDashboard(person: Admin | User) {
    if (isAdmin(person)) {
        // TypeScript knows `person` is an Admin here!
        console.log("Admin Privileges:", person.privileges); 
    } else {
        console.log("User Last Login:", person.lastLogin);
    }
}