Bird
Raised Fist0
Typescriptprogramming~15 mins

typeof type guards in Typescript - Deep Dive

Choose your learning style10 modes available
Overview - typeof type guards
What is it?
Typeof type guards are a way in TypeScript to check the type of a variable at runtime using the 'typeof' operator. They help the program understand what kind of value it is working with, like a string or number, so it can behave correctly. This check allows TypeScript to narrow down the possible types and provide safer code. It is especially useful when a variable can hold different types of values.
Why it matters
Without typeof type guards, TypeScript would not know the exact type of a variable during the program's execution, leading to errors or unsafe operations. This would make programs less reliable and harder to maintain. Type guards help catch mistakes early and allow developers to write code that adapts to different types safely, improving both developer confidence and user experience.
Where it fits
Before learning typeof type guards, you should understand basic TypeScript types and union types. After mastering typeof type guards, you can learn about other type guards like 'instanceof' and user-defined type guards, which provide more advanced ways to check types.
Mental Model
Core Idea
Typeof type guards let the program check a variable's type at runtime to safely narrow its possible types.
Think of it like...
It's like checking the label on a package before opening it to know if it contains clothes or books, so you handle it properly.
┌───────────────┐
│   Variable    │
│ (unknown type)│
└──────┬────────┘
       │ typeof check
       ▼
┌───────────────┐
│  Type narrowed│
│ (string, number│
│   etc.)       │
└───────────────┘
Build-Up - 6 Steps
1
FoundationUnderstanding basic typeof operator
🤔
Concept: Learn what the 'typeof' operator does in JavaScript and TypeScript.
The 'typeof' operator returns a string describing the type of a value. For example, typeof 5 returns 'number', and typeof 'hello' returns 'string'. This operator works at runtime and helps identify simple types like 'string', 'number', 'boolean', 'undefined', 'object', and 'function'.
Result
You can see the type of any value as a string, like 'number' or 'string'.
Knowing that 'typeof' returns a string describing the type is the foundation for using it as a type guard.
2
FoundationUnion types and the need for type narrowing
🤔
Concept: Understand why variables can have multiple types and why narrowing is needed.
In TypeScript, a variable can be declared to hold more than one type, called a union type, e.g., string | number. When you use such a variable, TypeScript doesn't know which type it currently holds. To safely use it, you need to narrow its type by checking it first.
Result
You realize that without checking, you can't safely call methods or operations specific to one type.
Understanding union types explains why type guards like 'typeof' are necessary to write safe code.
3
IntermediateUsing typeof for type narrowing in conditions
🤔Before reading on: do you think 'typeof' can narrow types inside an if statement? Commit to yes or no.
Concept: Learn how to use 'typeof' inside if statements to narrow variable types.
You can write code like: if (typeof value === 'string') { /* here value is string */ } else { /* here value is not string */ }. Inside the if block, TypeScript knows 'value' is a string and allows string-specific operations safely.
Result
TypeScript narrows the variable's type inside the if block based on the 'typeof' check.
Knowing that 'typeof' checks narrow types inside conditional blocks helps write safer, clearer code.
4
IntermediateCommon typeof type strings and their meanings
🤔Before reading on: do you think 'typeof null' returns 'null'? Commit to yes or no.
Concept: Learn the exact strings returned by 'typeof' and their quirks.
The common 'typeof' results are: 'string', 'number', 'boolean', 'undefined', 'object', 'function', and 'symbol'. Note that 'typeof null' returns 'object', which is a known JavaScript quirk. This means you need extra checks for null values.
Result
You understand which strings to check for and when extra care is needed.
Knowing the quirks of 'typeof' prevents bugs when checking for null or other special cases.
5
AdvancedCombining typeof with union types in functions
🤔Before reading on: do you think a function can safely handle multiple types using typeof checks? Commit to yes or no.
Concept: Use typeof type guards inside functions to handle different input types safely.
Example: function format(value: string | number) { if (typeof value === 'string') { return value.toUpperCase(); } else { return value.toFixed(2); } } Here, the function uses typeof to decide how to process the input based on its type.
Result
The function safely handles both strings and numbers without errors.
Understanding this pattern is key to writing flexible, type-safe functions.
6
ExpertLimitations and pitfalls of typeof type guards
🤔Before reading on: do you think 'typeof' can distinguish between arrays and objects? Commit to yes or no.
Concept: Explore what typeof cannot do and when it fails to narrow types correctly.
'typeof' returns 'object' for arrays, null, and objects, so it cannot distinguish them. For example, typeof [] === 'object' and typeof null === 'object'. This means you need other checks like Array.isArray() or explicit null checks to handle these cases.
Result
You learn when to combine typeof with other checks for accurate type narrowing.
Knowing the limits of 'typeof' guards prevents subtle bugs and improves type safety.
Under the Hood
At runtime, the JavaScript engine evaluates the 'typeof' operator on a value and returns a string representing its type. TypeScript uses this runtime information to narrow the static type of variables within conditional blocks. This narrowing is a compile-time feature that relies on the runtime 'typeof' result to safely allow or disallow operations on variables.
Why designed this way?
The 'typeof' operator existed in JavaScript for type checking at runtime. TypeScript leverages this existing operator to provide type narrowing without extra runtime cost. This design avoids reinventing type checks and keeps compatibility with JavaScript's dynamic nature.
┌───────────────┐
│   Variable    │
│ (unknown type)│
└──────┬────────┘
       │ runtime typeof
       ▼
┌───────────────┐
│  String result│
│  e.g. 'string'│
└──────┬────────┘
       │ compile-time
       ▼
┌───────────────┐
│ TypeScript    │
│ narrows type  │
│ in code block │
└───────────────┘
Myth Busters - 3 Common Misconceptions
Quick: does 'typeof null' return 'null'? Commit to yes or no before reading on.
Common Belief:Many believe 'typeof null' returns 'null'.
Tap to reveal reality
Reality:'typeof null' actually returns 'object' due to a historical JavaScript bug.
Why it matters:This causes confusion and bugs when checking for null values using 'typeof'.
Quick: can 'typeof' distinguish arrays from objects? Commit to yes or no before reading on.
Common Belief:Some think 'typeof' can tell arrays apart from objects.
Tap to reveal reality
Reality:'typeof' returns 'object' for both arrays and plain objects, so it cannot distinguish them.
Why it matters:Relying only on 'typeof' can cause wrong assumptions about data structures.
Quick: does 'typeof' work for custom classes? Commit to yes or no before reading on.
Common Belief:People often believe 'typeof' can identify custom class instances.
Tap to reveal reality
Reality:'typeof' returns 'object' for all objects, including class instances; it cannot identify the class type.
Why it matters:This limits 'typeof' usefulness for complex type checks, requiring other guards like 'instanceof'.
Expert Zone
1
TypeScript's control flow analysis remembers 'typeof' checks within nested blocks, allowing precise type narrowing even in complex conditions.
2
'typeof' checks are limited to primitive types and functions; for objects, combining with other checks is necessary for accurate typing.
3
Using 'typeof' in switch statements can improve readability and maintainability when handling multiple type cases.
When NOT to use
Do not use 'typeof' to distinguish between objects like arrays, null, or class instances. Instead, use Array.isArray(), explicit null checks, or 'instanceof' for classes. For complex type checks, user-defined type guards are better.
Production Patterns
In real-world code, 'typeof' guards are commonly used in input validation, API response handling, and utility functions to safely process values of multiple possible types. They are often combined with other checks to ensure robustness.
Connections
instanceof operator
complements typeof by checking object instances
Knowing 'typeof' handles primitives while 'instanceof' checks class instances helps cover all type checking needs.
union types
builds-on union types by narrowing them at runtime
Understanding union types is essential to appreciate why 'typeof' guards are needed to safely use variables with multiple possible types.
pattern matching in functional programming
similar concept of checking and narrowing types or values
Recognizing that 'typeof' guards are a form of pattern matching helps connect programming concepts across paradigms.
Common Pitfalls
#1Assuming 'typeof null' returns 'null' and skipping null checks.
Wrong approach:if (typeof value === 'null') { // handle null }
Correct approach:if (value === null) { // handle null }
Root cause:Misunderstanding that 'typeof null' returns 'object', not 'null'.
#2Using 'typeof' to check if a variable is an array.
Wrong approach:if (typeof value === 'object') { // assume array }
Correct approach:if (Array.isArray(value)) { // handle array }
Root cause:'typeof' returns 'object' for arrays, so it cannot distinguish them.
#3Expecting 'typeof' to identify custom class instances.
Wrong approach:if (typeof value === 'MyClass') { // handle MyClass }
Correct approach:if (value instanceof MyClass) { // handle MyClass }
Root cause:'typeof' only returns primitive type strings or 'object', never class names.
Key Takeaways
'typeof' type guards let TypeScript safely narrow variable types at runtime using simple string checks.
They work well for primitive types like string, number, and boolean but have limitations with objects and null.
Understanding the quirks of 'typeof', like 'typeof null' being 'object', is crucial to avoid bugs.
Combining 'typeof' with other checks like Array.isArray() or instanceof is necessary for complex types.
Mastering 'typeof' guards is a key step toward writing flexible, safe TypeScript code that handles multiple types.

Practice

(1/5)
1. What does the typeof operator do in TypeScript when used as a type guard?
easy
A. It declares a new variable with a specific type.
B. It converts a variable to a string type.
C. It checks the runtime type of a variable to narrow its type inside a condition.
D. It creates a new type alias for a variable.

Solution

  1. Step 1: Understand the purpose of typeof

    The typeof operator checks the actual type of a value at runtime, like 'string' or 'number'.
  2. Step 2: Recognize its use as a type guard

    Using typeof in an if condition helps TypeScript know the exact type inside that block, making code safer.
  3. Final Answer:

    It checks the runtime type of a variable to narrow its type inside a condition. -> Option C
  4. Quick Check:

    typeof narrows type [OK]
Hint: typeof checks actual type at runtime to narrow types [OK]
Common Mistakes:
  • Thinking typeof changes the variable's type
  • Confusing typeof with type declarations
  • Assuming typeof works at compile time only
2. Which of the following is the correct syntax to use typeof as a type guard in TypeScript?
easy
A. if (typeof x === 'string') { /* code */ }
B. if (typeof x = 'string') { /* code */ }
C. if (typeof x == string) { /* code */ }
D. if (typeof x === string) { /* code */ }

Solution

  1. Step 1: Check the correct comparison operator

    The strict equality operator === is required to compare typeof result with a string.
  2. Step 2: Verify the string literal format

    The type name must be a string literal like 'string', 'number', etc., inside quotes.
  3. Final Answer:

    if (typeof x === 'string') { /* code */ } -> Option A
  4. Quick Check:

    Correct typeof syntax uses === and quotes [OK]
Hint: Use === and quotes around type name in typeof checks [OK]
Common Mistakes:
  • Using single = instead of ===
  • Not putting type name in quotes
  • Using == instead of ===
3. What will be the output of this TypeScript code?
function checkValue(x: string | number) {
  if (typeof x === 'string') {
    return x.toUpperCase();
  } else {
    return x.toFixed(2);
  }
}
console.log(checkValue(3.14159));
medium
A. '3.14'
B. '3.14' as a string
C. '3.14' as a number
D. '3.14' as a string with two decimals

Solution

  1. Step 1: Identify the type of input

    The input is 3.14159, which is a number, so the else block runs.
  2. Step 2: Understand the else block behavior

    The else block calls toFixed(2) on the number, which returns a string with 2 decimals: '3.14'.
  3. Final Answer:

    '3.14' as a string with two decimals -> Option D
  4. Quick Check:

    Number input uses toFixed(2) = '3.14' [OK]
Hint: toFixed(2) returns string with 2 decimals [OK]
Common Mistakes:
  • Thinking toFixed returns a number
  • Confusing string and number outputs
  • Ignoring the else block
4. Find the error in this TypeScript code using typeof type guard:
function process(value: string | boolean) {
  if (typeof value === 'boolean') {
    return value.toUpperCase();
  } else {
    return value;
  }
}
medium
A. The typeof check should be for 'string' instead of 'boolean'.
B. Calling toUpperCase() on a boolean value causes an error.
C. The else block should convert value to boolean.
D. There is no error; the code is correct.

Solution

  1. Step 1: Analyze the typeof condition

    The condition checks if value is a boolean.
  2. Step 2: Check method call on boolean

    Inside the if block, it calls toUpperCase(), which exists only on strings, not booleans, causing an error.
  3. Final Answer:

    Calling toUpperCase() on a boolean value causes an error. -> Option B
  4. Quick Check:

    toUpperCase() invalid on boolean [OK]
Hint: Check method exists on type before calling [OK]
Common Mistakes:
  • Assuming booleans have string methods
  • Mixing up type guard conditions
  • Ignoring method compatibility
5. Given this function, what is the correct way to safely handle a variable that can be string, number, or boolean using typeof type guards?
function formatValue(val: string | number | boolean) {
  // Fill in the blanks
}
hard
A. Use separate if blocks: if typeof val === 'string', else if 'number', else if 'boolean', then handle each accordingly.
B. Use a single if block checking if typeof val === 'string' and treat others as strings.
C. Convert val to string directly without typeof checks.
D. Use typeof val === 'object' to handle all types.

Solution

  1. Step 1: Recognize multiple possible types

    The variable can be string, number, or boolean, so each needs separate handling.
  2. Step 2: Use multiple typeof checks

    Use if-else if blocks checking typeof val === 'string', 'number', and 'boolean' to safely handle each type.
  3. Final Answer:

    Use separate if blocks: if typeof val === 'string', else if 'number', else if 'boolean', then handle each accordingly. -> Option A
  4. Quick Check:

    Multiple typeof checks for multiple types [OK]
Hint: Check each type separately with typeof for safety [OK]
Common Mistakes:
  • Handling all types as strings blindly
  • Using typeof 'object' for primitives
  • Skipping boolean type handling
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard