# TypeScript Type Guards and Narrowing

TypeScript's type system allows variables to have multiple possible types (Unions). **Narrowing** is the process of refining a broad type (like `string | number`) into a specific type (like `string`) within a specific block of code.

## 1. Built-in Type Guards

TypeScript automatically understands standard JavaScript checks.

### `typeof`
Used for primitives (`string`, `number`, `boolean`, `symbol`).

```typescript
function printId(id: number | string) {
  if (typeof id === "string") {
    // In this block, TypeScript knows 'id' is a string
    console.log(id.toUpperCase());
  } else {
    // Here, 'id' must be a number
    console.log(id.toFixed(2));
  }
}
```

### `instanceof`
Used for classes and objects constructed with `new`.

```typescript
class Dog {
  bark() { console.log("Woof!"); }
}

class Cat {
  meow() { console.log("Meow!"); }
}

function interact(pet: Dog | Cat) {
  if (pet instanceof Dog) {
    pet.bark(); // OK
  } else {
    pet.meow(); // OK
  }
}
```

### `in` operator
Checks if a property exists on an object.

```typescript
type Fish = { swim: () => void };
type Bird = { fly: () => void };

function move(animal: Fish | Bird) {
  if ("swim" in animal) {
    animal.swim();
  } else {
    animal.fly();
  }
}
```

## 2. User-Defined Type Guards (Type Predicates)

Sometimes TypeScript can't figure out the type automatically. You can write a function that returns a **type predicate**.

The return type syntax is `parameterName is Type`.

```typescript
interface Fish { swim: () => void; }
interface Bird { fly: () => void; }

// Custom Type Guard
function isFish(pet: Fish | Bird): pet is Fish {
  return (pet as Fish).swim !== undefined;
}

function move(pet: Fish | Bird) {
  if (isFish(pet)) {
    pet.swim(); // TypeScript knows pet is Fish here
  } else {
    pet.fly();  // TypeScript knows pet is Bird here
  }
}
```

## 3. Discriminated Unions

This is a powerful pattern where every type in a union has a common literal property (the "discriminant"), usually called `kind` or `type`.

```typescript
interface Circle {
  kind: "circle";
  radius: number;
}

interface Square {
  kind: "square";
  sideLength: number;
}

type Shape = Circle | Square;

function getArea(shape: Shape) {
  switch (shape.kind) {
    case "circle":
      // TypeScript knows this is a Circle
      return Math.PI * shape.radius ** 2;
    case "square":
      // TypeScript knows this is a Square
      return shape.sideLength ** 2;
  }
}
```

[[programming/javascript/typescript/typescript]]