JavaScript > TypeScript > Advanced TypeScript > Type guards
TypeScript Type Guards: Narrowing Types for Safer Code
Explore TypeScript type guards to refine variable types within conditional blocks, ensuring type safety and enabling specific operations based on type checks. This guide offers practical examples and best practices for effective type narrowing.
Understanding Type Guards
Type guards are TypeScript functions that narrow down the type of a variable within a conditional block. They enable the TypeScript compiler to understand more precisely what type a variable holds, leading to more accurate type checking and fewer errors. Without type guards, TypeScript might not allow you to perform certain operations on a variable because it can't be sure of its type. Type guards provide that certainty.
Basic Type Guard Example: 'typeof' Operator
This example uses the typeof operator as a type guard. Inside the if block, TypeScript infers that input is a string, allowing you to access its length property. In the else block, TypeScript knows it's a number, so you can use toFixed().
function printLength(input: string | number) {
  if (typeof input === 'string') {
    // Within this block, TypeScript knows 'input' is a string
    console.log(input.length);
  } else {
    // Within this block, TypeScript knows 'input' is a number
    console.log(input.toFixed(2));
  }
}Custom Type Guards: Using Type Predicates
Here, we define a custom type guard function isBird. The return type pet is Bird is a type predicate.  If isBird(pet) returns true, TypeScript knows that pet is of type Bird within the if block. If it returns false, TypeScript knows it is a Fish.
interface Bird {
  fly(): void;
  layEggs(): void;
}
interface Fish {
  swim(): void;
  layEggs(): void;
}
function isBird(pet: Bird | Fish): pet is Bird {
  return (pet as Bird).fly !== undefined;
}
function careForPet(pet: Bird | Fish) {
  if (isBird(pet)) {
    pet.fly();
  } else {
    pet.swim();
  }
}Using the 'in' Operator as a Type Guard
The in operator checks if a property exists on an object. In this example, if 'radius' in shape returns true, TypeScript infers that shape is a Circle. Otherwise, it's a Square.
interface Circle {
  radius: number;
}
interface Square {
  sideLength: number;
}
type Shape = Circle | Square;
function getArea(shape: Shape) {
  if ('radius' in shape) {
    return Math.PI * shape.radius * shape.radius; // TypeScript knows 'shape' is a Circle
  } else {
    return shape.sideLength * shape.sideLength; // TypeScript knows 'shape' is a Square
  }
}Real-Life Use Case: Handling API Responses
Type guards are useful when dealing with API responses that can be either successful or erroneous. Checking the success property allows you to narrow down the type and handle the response accordingly.
interface SuccessResponse {
  success: true;
  data: any;
}
interface ErrorResponse {
  success: false;
  error: string;
}
type ApiResponse = SuccessResponse | ErrorResponse;
function handleResponse(response: ApiResponse) {
  if (response.success) {
    console.log('Data:', response.data);
  } else {
    console.error('Error:', response.error);
  }
}Best Practices
isString, isNumber, isUser).
Interview Tip
When discussing type guards in an interview, be prepared to explain the purpose of type narrowing, how type guards achieve this, and the different techniques for implementing them (typeof, instanceof, custom type predicates, and the in operator).  Also, be prepared to discuss the trade-offs of using type guards versus other type-checking techniques.
When to Use Them
Use type guards when you need to perform operations that are specific to certain types within a union. They are particularly useful when dealing with:
Alternatives
Alternatives to type guards include:
Pros
Cons
FAQ
- 
                        What happens if I don't use a type guard when working with a union type?
 TypeScript might prevent you from performing certain operations on the variable because it cannot be sure of its type. You might encounter type errors at compile time.
- 
                        Can I use type guards with classes?
 Yes, you can use theinstanceofoperator as a type guard to check if an object is an instance of a particular class.
- 
                        Are type guards a runtime or compile-time feature?
 Type guards primarily affect TypeScript's compile-time type checking. While the type guard functions themselves are executed at runtime, their main purpose is to provide type information to the compiler.
