Editor’s note: This article was last updated on 15 January 2024 to include the use of the TypeScript is operator. It also now covers the creation of custom type guards and information about how to inspect objects with type guards.
A type guard is a TypeScript technique used to get information about the type of a variable, usually within a conditional block. Type guards are regular functions that return a Boolean, taking a type and telling TypeScript if it can be narrowed down to something more specific. Type guards have the unique property of assuring that the value tested is of a set type depending on the returned Boolean.
TypeScript uses built-in JavaScript operators like typeof, instanceof, and in to determine if an object contains a property. Type guards enable you to instruct the TypeScript compiler to infer a specific type for a variable in a particular context. This process validates that the type of an argument aligns with the specified type, enhancing type accuracy and code reliability.
Type guards are typically used for narrowing a type and are quite similar to feature detection, allowing you to detect the correct methods, prototypes, and properties of a value. Therefore, you can easily figure out how to handle that value.
The Replay is a weekly newsletter for dev and engineering leaders.
Delivered once a week, it's your curated guide to the most important conversations around frontend dev, emerging AI tools, and the state of modern software.
instanceof type guardinstanceof is a built-in type guard that can be used to check if a value is an instance of a given constructor function or class. With this type guard, we can test if an object or value is derived from a class, which is useful for determining the type of an instance type.
The basic syntax for the instanceof type guard is below:
objectVariable instanceof ClassName;
In the example below, we see an example of the instanceof type guard:
interface Accessory {
brand: string;
}
class Necklace implements Accessory{
kind: string;
brand: string;
constructor(brand: string, kind: string) {
this.brand = brand;
this.kind = kind;
}
}
class bracelet implements Accessory{
brand: string;
year: number;
constructor(brand: string, year: number) {
this.brand = brand;
this.year = year;
}
}
const getRandomAccessory = () =>{
return Math.random() < 0.5 ?
new bracelet('cartier', 2021) :
new Necklace('choker', 'TASAKI');
}
let Accessory = getRandomAccessory();
if (Accessory instanceof bracelet) {
console.log(Accessory.year);
}
if (Accessory instanceof Necklace) {
console.log(Accessory.brand);
}
The getRandomAccessory function above returns either a Necklace or bracelet object, as they both implement the Accessory interface. The constructor signatures for both Necklace and bracelet are different, and the instanceof type guard compares both constructor signatures to effectively determine the type.
typeof type guardThe typeof type guard is used to determine the type of a variable. The typeof type guard is said to be very limited and shallow; it can only determine the following types recognized by JavaScript:
booleanstringbigintsymbolundefinedfunctionnumberFor anything outside of this list, the typeof type guard simply returns object.
The typeof type guard can be written in the following two ways:
typeof v !== "typename" #or typeof v === "typename"
typename can be a string, number, symbol, or boolean.
In the example below, StudentId has a string | number type union parameter entry. We see that if the variable is a string, Student is printed, and if it is a number, Id is printed. The typeof type guard helps us to extract the type from x:
function StudentId(x: string | number) {
if (typeof x == 'string') {
console.log('Student');
}
if (typeof x === 'number') {
console.log('Id');
}
}
StudentId(`446`); //prints Student
StudentId(446); //prints Id
in type guardThe in type guard checks if an object has a particular property, using that to differentiate between different types. It usually returns a Boolean, which indicates if the property exists in that object. It is used for its narrowing features, as well as to check for browser support.
The basic syntax for the in type guard is below:
propertyName in objectName
In the example below, the in type guard checks if the property house exists. In cases where it does exist, the Boolean true is returned, and where it does not exist, false is returned:
"house" in { name: "test", house: { parts: "door" } }; // => true
"house" in { name: "test", house: { parts: "windows" } }; // => true
"house" in { name: "test", house: { parts: "roof" } }; // => true
"house" in { name: "test" }; // => false
"house" in { name: "test", house: undefined }; // => true
Another similar example of how the in type guard works is shown below:
interface Pupil {
ID: string;
}
interface Adult {
SSN: number;
}
interface Person {
name: string;
age: number;
}
let person: Pupil | Adult | Person = {
name: 'Britney',
age: 6
};
const getIdentifier = (person: Pupil | Adult | Person) => {
if ('name' in person) {
return person.name;
}
else if ('ID' in person) {
return person.ID
}
return person.SSN;
}
is operatorThe is operator checks if a value or variable is of a specific type. It is a type guard that can be used to narrow the type of a variable or expression. It is often used with a user-defined type guard function to narrow down the type of a variable within a specific code block.
This operator allows you to check whether a value is a certain type at runtime by type testing. This is particularly useful when you want to ensure that a variable has a specific type before performing certain operations on it.
The basic syntax for the is operator is as follows:
variablename is typename
Here is a simple example of the is operator in action:
interface Cat {
meow(): void;
}
interface Dog {
bark(): void;
}
function isCat(pet: Dog | Cat): pet is Cat {
return (pet as Cat).meow !== undefined;
}
let pet: Dog | Cat;
// Using the 'is' keyword
if (isCat(pet)) {
pet.meow();
} else {
pet.bark();
}
The code above checks the type of the variable pet and performs different actions based on its type. If pet is of type Cat, it calls the meow() method. If pet is of type Dog, it calls the bark() method.
The isCat() function is a type guard that checks if pet is of type Cat by checking if the meow() method exists on pet. If it does, the function returns true, indicating that pet is of type Cat. Otherwise, it returns false. The is keyword is used to perform the type check in the if statement.
Equality narrowing checks for the value of an expression. For two variables to be equal, they must both be of the same type. If the type of a variable is unknown, but it is equal to another variable with a precise type, then TypeScript will narrow the type of the first variable with the information the well-known variable provides:
function getValues(a: number | string, b: string) {
if(a === b) {
// this is where the narrowing takes place. narrowed to string
console.log(typeof a) // string
} else {
// if there is no narrowing, type remains unknown
console.log(typeof a) // number or string
}
}
If variable a is equal to variable b, then both have to have the same type. In this case, TypeScript narrows it down to string. Without narrowing, the type of a is still unclear because it could either be a number or a string.
Creating a custom type guard is typically the most powerful option for using type guards. When you create a custom type guard by writing it yourself, there are no limits to what you can check. However, if the custom type guard is written incorrectly, it can cause many errors. Therefore, precision is key.
An example of a custom type guard is shown below:
interface Necklace{
kind: string;
brand: string;
}
interface bracelet{
brand: string;
year: number;
}
type Accessory = Necklace | bracelet;
const isNecklace = (b: Accessory): b is Necklace => {
return (b as Necklace).kind !== undefined
}
const Necklace: Accessory = {kind: "Choker", brand: "TASAKI"};
const bracelet: Accessory = {brand: "Cartier", year: 2021};
console.log(isNecklace(bracelet)) //Logs false
console.log(isNecklace(Necklace)) //Logs true
In the code above, the type predicate b is Necklace will make TypeScript reduce the type to Necklace instead of returning just a Boolean value.
TypeScript custom type guards are functions that enable you to check the type of a value or expression at runtime. They are useful for verifying more complex types or conditions that can’t be easily checked using built-in type guards like some we have already explored.
Custom type guards can be used in conditional expressions and other parts of your code where you need to check the type of a value or expression.
Custom type guards allow you to check for more complex types and conditions and generally improve the readability of your code.
Here is an example of a custom type guard:
function isBaby(obj: any): obj is Baby {
return typeof obj === "object" && obj !== null && "sound" in obj;
}
interface Baby {
sound: string;
}
function makeSound(baby: any) {
if (isBaby(baby)) {
console.log("Making a sound:", baby.sound);
} else {
console.log("Not a valid baby.");
}
}
Above, the function makeSound takes the argument baby of type any. It checks if the baby object satisfies the isBaby type guard, which checks if the object has a property called sound. If the baby object satisfies the isBaby type guard, it logs the sound of the baby to the console. Otherwise, it logs “Not a valid baby.” to the console.
isBaby is our custom type guard function. It checks if an object has a sound property, which is characteristic of a baby.
Type guards can be used to inspect or check the type of an object. Type guards can be used to check the specific properties an object has, thus allowing us to perform operations specific to those properties.
We can also use type guards to check if an object is of a particular type, like a number, string, or a specific class:
function isCar(vehicle: any): vehicle is Car {
return (
typeof vehicle === "object" &&
vehicle !== null &&
"brand" in vehicle &&
"model" in vehicle &&
"year" in vehicle
);
}
interface Car {
brand: string;
model: string;
year: number;
}
function inspectVehicle(vehicle: any) {
if (isCar(vehicle)) {
// Inside this block, TypeScript knows that 'vehicle' is of type 'Car'
console.log("Brand:", vehicle.brand);
console.log("Model:", vehicle.model);
console.log("Year:", vehicle.year);
} else {
console.log("Not a valid car object.");
}
}
The code above checks if a given object is of type Car. It includes an interface Car that defines the properties brand, model, and year. It also includes a function inspectVehicle that takes an object as a parameter and checks if it is a Car using the isCar type guard function. If it is a Car, it logs the brand, model, and year of the vehicle. Otherwise, it logs that it is not a valid car object.
We use the inspectVehicle function to check if the vehicle parameter is indeed a Car. If the vehicle is a Car, it logs the brand, model, and year of the vehicle. If the vehicle is not a Car, it logs that it is not a valid car object.
We can test with a car object as seen in the code block below:
const myCar = {
brand: "Toyota",
model: "Camry",
year: 2020
};
inspectVehicle(myCar);
Or test with a non-car object as seen here:
const myBike = { type: "Mountain Bike", wheels: 2 };
inspectVehicle(myBike);
TypeScript type guards help assure the value of a type, improving the overall code flow. In this article, we reviewed several of the most helpful type guards in TypeScript, exploring a few examples to see them in action.
Oftentimes, your use case can be solved using either the instanceof type guard, the typeof type guard, or the in type guard. However, you can use a custom type guard when it is necessary.
I hope you enjoyed this article! Be sure to leave a comment if you have any questions.
LogRocket lets you replay user sessions, eliminating guesswork by showing exactly what users experienced. It captures console logs, errors, network requests, and pixel-perfect DOM recordings — compatible with all frameworks, and with plugins to log additional context from Redux, Vuex, and @ngrx/store.
With Galileo AI, you can instantly identify and explain user struggles with automated monitoring of your entire product experience.
Modernize how you understand your web and mobile apps — start monitoring for free.

Compare the top AI development tools and models of November 2025. View updated rankings, feature breakdowns, and find the best fit for you.

Discover what’s new in The Replay, LogRocket’s newsletter for dev and engineering leaders, in the November 5th issue.

A senior developer discusses how developer elitism breeds contempt and over-reliance on AI, and how you can avoid it in your own workplace.

Examine AgentKit, Open AI’s new tool for building agents. Conduct a side-by-side comparison with n8n by building AI agents with each tool.
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up now
7 Replies to "How to use type guards in TypeScript"
It is recommended to name variables camelCase and class/interface/types PascalCase
Nice post.
The section on the typeof operator is somewhat incorrect. I can be string, number, boolean, or symbol ALONG WITH function, object, and bigint.
The section “The typeof type guard” may mislead the readers unless the author corrects those type with the lowercased types.
That’s a fair point, thanks for the suggestion
Crazy language… The only way to really check for union typed classInstance is to have some unique filed name in it and do “if (uniqueFieldName in classInstance)”… *blarghhhhh
AI generated article..