What is a "type guard"?
What a Type Guard is
A type guard is a logical expression or function that helps TypeScript refine the type of a variable in a particular branch of code.
Put simply: a type guard is a way to "tell the compiler who I really am".
Example without a type guard
function printId(id: string | number) {
console.log(id.toUpperCase()); // Error - id might be a number
}TypeScript doesn't know whether id is a string or a number.
With a Type Guard
function printId(id: string | number) {
if (typeof id === "string") {
// here id: string
console.log(id.toUpperCase());
} else {
// here id: number
console.log(id.toFixed(2));
}
}The check typeof id === "string" is a built-in type guard.
TS automatically narrows the type inside each branch.
Main kinds of Type Guards
| Kind | Check | Example |
|---|---|---|
typeof | for primitives | typeof value === "string" |
instanceof | for classes and constructors | value instanceof Date |
in | checking whether a property exists | "prop" in obj |
A custom v is Type function | a custom type guard | isString(value): value is string |
1. A type guard via typeof
Used to check primitive types:
"string", "number", "boolean", "symbol", "undefined", "object", "function".
function process(val: string | number | boolean) {
if (typeof val === "string") {
// val: string
console.log(val.toUpperCase());
} else if (typeof val === "number") {
// val: number
console.log(val.toFixed(2));
} else {
// val: boolean
console.log(val ? "true" : "false");
}
}2. A type guard via instanceof
Used to check whether an object was created by a specific class or constructor.
function logDate(value: Date | string) {
if (value instanceof Date) {
// value: Date
console.log(value.toISOString());
} else {
// value: string
console.log(value.toUpperCase());
}
}3. A type guard via the in operator
Checks whether an object has a specific property, and TS narrows the type depending on the result.
type Car = { drive: () => void };
type Boat = { sail: () => void };
function move(vehicle: Car | Boat) {
if ("drive" in vehicle) {
// vehicle: Car
vehicle.drive();
} else {
// vehicle: Boat
vehicle.sail();
}
}4. Custom type guards (v is Type)
You can declare your own function that returns a boolean and tells TypeScript
that if it returns true, the argument has a specific type.
Syntax:
function isDog(pet: Animal): pet is Dog {
return (pet as Dog).bark !== undefined;
}Usage example:
type Dog = { bark: () => void };
type Cat = { meow: () => void };
function isDog(animal: Dog | Cat): animal is Dog {
return (animal as Dog).bark !== undefined;
}
function makeSound(animal: Dog | Cat) {
if (isDog(animal)) {
animal.bark(); // animal: Dog
} else {
animal.meow(); // animal: Cat
}
}Here the expression
animal is Dogtells TS: "If the function returned true, then animal is definitely a Dog from here on".
Type guards and narrowing
Type guards are the main mechanism through which type narrowing happens. In effect:
Type guard → triggers narrowing.
An advanced example
type Shape =
| { kind: "circle"; radius: number }
| { kind: "square"; side: number };
function isCircle(s: Shape): s is { kind: "circle"; radius: number } {
return s.kind === "circle";
}
function area(shape: Shape) {
if (isCircle(shape)) {
// shape: circle
return Math.PI * shape.radius ** 2;
} else {
// shape: square
return shape.side ** 2;
}
}Real-world use cases
- Validating data after parsing JSON
- Checking API responses (runtime type checking)
- Filtering arrays by type
- Working with union types and discriminated unions
- Narrowing when working with
unknownandany
Example: filtering an array
function isString(value: unknown): value is string {
return typeof value === "string";
}
const mixed = [1, "a", 2, "b", true];
const strings = mixed.filter(isString);
// strings: string[]Summary
| Term | Definition |
|---|---|
| Type Guard | A check that helps TypeScript determine the specific type of a value |
| Goal | Narrowing union or unknown types |
| Kinds | typeof, instanceof, in, custom (value is Type) |
| Main benefit | Safe access to properties and methods of specific types without casts (as) |
Put simply:
A Type Guard is a "guard" that stands in the path of a union type and tells TypeScript: "Don't worry, I checked, now we know exactly who this is".
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.