`typeof`, `instanceof`, `in` — and Manual Guards
Type Guards
Type guards are the operators TypeScript recognizes for narrowing. Plus a way to write your own.
What you'll learn
- Narrow with `instanceof` and `in`
- Combine guards
- Write a user-defined guard
The built-in narrowers TS recognizes. Each one tells TS something specific.
typeof — Primitives
Covered in the previous lesson. Use for string, number,
boolean, function, undefined.
instanceof — Class Instances
function describeError(e: Error | string) {
if (e instanceof Error) {
// e is Error
console.log(e.message);
} else {
// e is string
console.log(e);
}
} instanceof X narrows to “instance of class X”.
in — Property Existence
type Dog = { bark: () => void };
type Cat = { meow: () => void };
function speak(pet: Dog | Cat) {
if ("bark" in pet) {
pet.bark(); // pet is Dog
} else {
pet.meow(); // pet is Cat
}
} in checks whether a property exists. Useful for distinguishing
union members by their unique fields.
Equality Narrowing for Objects
function status(x: { state: "ok" } | { state: "error" }) {
if (x.state === "ok") {
// x is { state: "ok" }
} else {
// x is { state: "error" }
}
} The most useful narrowing — narrowing on a discriminator field. Discriminated unions get a full lesson soon.
Combined Guards
function safe(x: string | number | null) {
if (x != null && typeof x === "string") {
// x is string
}
} x != null (with !=, not !==) rules out BOTH null and
undefined. Then typeof narrows further.
User-Defined Guards
For checks the compiler can’t figure out, write your own — covered in detail next lesson.
Recap
| Tool | When |
|---|---|
typeof | Primitive types (string, number, etc.) |
instanceof | Class instances |
in | An object has a specific key |
=== / !== | Literal-value narrowing |
| Truthiness | Rules out falsy values |
| User-defined | Custom checks (next lesson) |
Up Next
When the built-in guards aren’t enough — write a function that guarantees a type.
Type Predicates →