TypeScript's control-flow analysis watches conditional checks and progressively narrows a variable's type within each branch — a typeof check narrows a union to one specific primitive type, instanceof narrows to a specific class, and the in operator narrows based on whether a named property exists on the value. This happens automatically from ordinary JavaScript runtime checks; no special TypeScript-only syntax is required.
typeof narrowing
Inside each branch of the check, TypeScript treats value as exactly the narrowed type — no cast or assertion needed.
function format(value: string | number) {
if (typeof value === "string") {
return value.toUpperCase(); // TypeScript knows: value is string here
}
return value.toFixed(2); // TypeScript knows: value is number here
}instanceof and in narrowing
instanceof narrows to a specific class; in narrows based on whether a property exists, useful for distinguishing object shapes without a class hierarchy at all.
class Dog { bark() { return "Woof"; } }
class Cat { meow() { return "Meow"; } }
function speak(animal: Dog | Cat) {
if (animal instanceof Dog) {
return animal.bark(); // narrowed to Dog
}
return animal.meow(); // narrowed to Cat
}
type Fish = { swim: () => void };
type Bird = { fly: () => void };
function move(pet: Fish | Bird) {
if ("swim" in pet) {
pet.swim(); // narrowed to Fish
} else {
pet.fly(); // narrowed to Bird
}
}Discriminated unions: the cleanest pattern
A shared literal-type property (here, kind) lets TypeScript narrow an entire union precisely from one check, and a switch over that property gets exhaustiveness checking almost for free — this is widely considered the most robust narrowing pattern for anything beyond a couple of simple cases.
type Circle = { kind: "circle"; radius: number };
type Square = { kind: "square"; side: number };
type Shape = Circle | Square;
function area(shape: Shape): number {
switch (shape.kind) {
case "circle": return Math.PI * shape.radius ** 2; // narrowed to Circle
case "square": return shape.side ** 2; // narrowed to Square
}
}