Type Narrowing and Runtime Behavior
Types exist only at compile time. They are erased before your code runs. This section covers what that means in practice and how to use type narrowing to work safely with broad types.
Types Are Erased at Runtime
All type information is removed during compilation. The compiled JavaScript knows nothing about your types, interfaces, or type aliases.
This means you cannot use TypeScript types for runtime checks:
interface User {
name: string;
age: number;
}
function isUser(value: unknown): boolean {
return value instanceof User;
// Error: 'User' only refers to a type,
// but is being used as a value here
}
Interfaces and type aliases do not exist at runtime. They produce no JavaScript output at all. If you need runtime type checking, you have to write actual JavaScript checks:
function isUser(value: unknown): value is User {
if (typeof value !== "object" || value === null) {
return false;
}
const candidate = value as { name?: unknown; age?: unknown };
return (
typeof candidate.name === "string" && typeof candidate.age === "number"
);
}
The value is User return type is a type predicate. It tells TypeScript that if this function returns true, the value can be safely treated as a User.
Type Narrowing and Type Guards
Type narrowing is the process of refining a broad type to a more specific one using runtime checks. TypeScript understands several narrowing patterns:
typeof Guards
function double(value: string | number): string | number {
if (typeof value === "string") {
return value.repeat(2); // TypeScript knows: string
}
return value * 2; // TypeScript knows: number
}
double("ha"); // "haha"
double(21); // 42
The in Operator
type Fish = { swim: () => void };
type Bird = { fly: () => void };
function move(animal: Fish | Bird) {
if ("swim" in animal) {
animal.swim(); // TypeScript knows: Fish
} else {
animal.fly(); // TypeScript knows: Bird
}
}
instanceof Guards
function formatDate(input: string | Date): string {
if (input instanceof Date) {
return input.toISOString(); // TypeScript knows: Date
}
return input; // TypeScript knows: string
}