Back to Blog
Lesson 16 of the TypeScript: Typing JavaScript with Confidence course
TypeScriptAugust 3, 20264 min read

Mastering the Typeof Guard in TypeScript for Runtime Safety

Learn how to use the typeof guard in TypeScript to safely narrow union types at runtime. Improve your type safety and eliminate runtime errors today.

TypeScriptType SafetyTypeofNarrowingRuntimeProgramming Basics
Detailed view of a padlock securing a metal gate with a chain, emphasizing safety and security.

Previously in this course, we explored Type Narrowing with Conditionals in TypeScript to handle basic logic flow. While those techniques help us manage broad categories, we often encounter scenarios where we need to distinguish between specific data types—like a string versus a number—at runtime.

This is where the typeof guard comes in. It is one of the most fundamental tools for refining your types when you are dealing with Union Types for Flexibility in TypeScript.

What is a Typeof Guard?

In JavaScript, the typeof operator returns a string representing the type of an unevaluated operand. TypeScript leverages this existing JavaScript behavior to perform "control flow analysis."

When you use typeof inside a conditional block, TypeScript "narrows" the variable's type based on that check. This tells the compiler, "Inside this specific block, I have verified the data is a string, so treat it as such."

Why This Matters for Runtime Safety

TypeScript types disappear at compile time. However, our application often receives data from APIs or user inputs that could be one of several types. If you try to call .toUpperCase() on a value that might be a number, your code will crash at runtime. Using a typeof guard prevents these errors before they can reach your users.

Implementing Typeof Guards: A Worked Example

Close-up of a smartphone with ChatGPT interface on a speckled surface, highlighting technology and AI.

Imagine our task API client needs to handle a taskId that could arrive as either a string (a UUID) or a number (a legacy database ID).

TYPESCRIPT
type TaskIdentifier = string | number;

function getTaskDetails(id: TaskIdentifier) {
  // TypeScript doesn't know if id is string or number here
  // id.toUpperCase(); // Error: Property CE9178">'toUpperCase' does not exist on type CE9178">'number'

  if (typeof id === "string") {
    // Inside this block, TypeScript knows id is a string
    console.log(CE9178">`Fetching task with UUID: ${id.toUpperCase()}`);
  } else {
    // Inside this block, TypeScript knows id must be a number
    console.log(CE9178">`Fetching task with legacy ID: ${id.toFixed(0)}`);
  }
}

By adding that typeof check, we’ve effectively "guarded" our code. We have narrowed the union type TaskIdentifier into its specific components, allowing us to safely call methods specific to those types.

Hands-on Exercise

Update your task client logic. Create a function called formatAssignee that accepts a parameter which can be a string (a name) or null (if unassigned).

  1. Write the function to accept string | null.
  2. Use a typeof guard to check if the value is a string.
  3. If it is, return the name in uppercase.
  4. If it is null, return the string "Unassigned".

Common Pitfalls

Even experienced engineers trip up on these nuances. Keep these two rules in mind:

  • The typeof null Quirk: In JavaScript, typeof null returns "object". This is a long-standing language bug. If you are checking for null, do not use typeof. Use a direct comparison like if (val === null).
  • Over-guarding: You don't need to use a guard if TypeScript already knows the type. If you have already narrowed a type earlier in the function, don't add redundant typeof checks; it makes your code harder to read.
  • Objects and Arrays: typeof isn't very helpful for distinguishing between different object shapes (e.g., distinguishing a Task object from a User object). For those scenarios, we will look at more advanced techniques like the in operator, which we'll cover in the next lesson.

Frequently Asked Questions

Does typeof work on custom interfaces?

No. typeof only recognizes JavaScript primitives (string, number, bigint, boolean, symbol, undefined, object, and function). For custom interfaces, you'll need TypeScript Type Guards: Stop Runtime Data Corruption in API Calls.

Can I use typeof with const variables?

Yes, but since const variables often have narrow literal types, the compiler will often infer the type automatically without needing a guard. Guards are most useful for function parameters or variables with union types.

Recap

The typeof guard is your primary defense when dealing with mixed-type data. By wrapping your logic in a simple conditional check, you provide the compiler with the information it needs to ensure type safety. You’ve now moved from guessing what a variable might be to explicitly verifying it at runtime.

Up next: The In Operator for Object Narrowing.

Similar Posts