Skip to main content

Type Narrowing

Whenever you handle variables classified as Unions (string | number) or completely mysterious Types (unknown), TypeScript will lock you out from utilizing specific methods.

Before we can use .toUpperCase() on a Union natively, we must write logical Type Guards to systematically eliminate alternative potential outcomes. This process is called Type Narrowing.

1. The typeof Guard​

The quickest way to structurally narrow primitive types natively.

function processLength(input: string | number[]) {
// At this point, TS doesn't know if 'input' is a string or an Array.

// NARROWING:
if (typeof input === "string") {
// Inside this specific block, TS mathematically guarantees 'input' is a string!
return input.length;
} else {
// Since it wasn't a string, TS logically infers it MUST be an array smoothly here.
return input.length;
}
}

2. Truthiness Narrowing​

Checking if a value inherently exists to eliminate null or undefined variants perfectly.

function printEmails(emails: string[] | null) {
// If 'emails' is null, it evaluates heavily as falsy cleanly!
if (!emails) {
console.log("No emails found!");
return;
}

// Down here, TS successfully dropped 'null' from the Union cleanly.
emails.forEach(e => console.log(e));
}

3. The instanceof Guard​

Used gracefully to narrow downward into specialized instantiated Class logical objects dynamically.

class Car { drive() {} }
class Boat { float() {} }

function operateVehicle(vehicle: Car | Boat) {
if (vehicle instanceof Boat) {
vehicle.float();
} else {
vehicle.drive();
}
}