Type Narrowing
Narrowing is the process of refining a broad type to a more specific one based on runtime checks. TypeScript understands these checks and adjusts the type accordingly.
typeof guard
ts
function process(value: string | number) {
if (typeof value === 'string') {
return value.toUpperCase(); // string here
}
return value.toFixed(2); // number here
}instanceof guard
ts
function handleError(error: unknown) {
if (error instanceof Error) {
console.log(error.message); // Error here
}
}in operator
ts
type Cat = { meow(): void };
type Dog = { bark(): void };
function makeSound(animal: Cat | Dog) {
if ('meow' in animal) {
animal.meow(); // Cat here
} else {
animal.bark(); // Dog here
}
}Discriminated unions
ts
type Shape =
| { kind: 'circle'; radius: number }
| { kind: 'rect'; width: number; height: number };
function area(shape: Shape) {
switch (shape.kind) {
case 'circle': return Math.PI * shape.radius ** 2;
case 'rect': return shape.width * shape.height;
}
}Type predicates
ts
function isString(value: unknown): value is string {
return typeof value === 'string';
}Discriminated unions + exhaustive switch is the most powerful narrowing pattern - TypeScript will warn you if a case is missing.
updated
did you know it?