Hone logo
Hone
Problems

Safe Type Checking with Type Guards in TypeScript

TypeScript's static typing is a powerful tool, but sometimes you'll encounter situations where you receive data from external sources (like user input, APIs, or other functions) that don't perfectly match your expected types. Type guards allow you to narrow down the type of a variable within a specific scope, ensuring type safety and preventing runtime errors. This challenge will test your understanding of how to create and utilize type guards effectively.

Problem Description

You are tasked with building a system that processes data representing different types of vehicles. The data arrives as a generic Vehicle type, which can be either a Car or a Bicycle. Your goal is to write functions that can safely determine the type of a Vehicle and then access its specific properties without encountering TypeScript errors. You must implement type guards to achieve this.

Key Requirements:

  • Define Interfaces: Create Car and Bicycle interfaces with appropriate properties (e.g., Car has numDoors, Bicycle has hasBasket).
  • Define a Union Type: Create a Vehicle type that is a union of Car and Bicycle.
  • Implement Type Guards: Write two type guard functions, isCar and isBicycle, that take a Vehicle as input and return a boolean indicating whether it's a Car or a Bicycle, respectively. These functions should use in operator or typeof to check for specific properties.
  • Safe Property Access: Write a function processVehicle that takes a Vehicle as input. Inside this function, use the isCar and isBicycle type guards to conditionally access properties of the vehicle, ensuring type safety.

Expected Behavior:

  • The isCar function should return true if the input Vehicle is a Car and false otherwise.
  • The isBicycle function should return true if the input Vehicle is a Bicycle and false otherwise.
  • The processVehicle function should correctly access and log the appropriate properties based on the vehicle type, without TypeScript errors.

Edge Cases to Consider:

  • Handle cases where the input Vehicle might not have any of the expected properties. While not strictly required to handle these cases (i.e., throw an error), your type guards should correctly identify the type even if properties are missing.
  • Consider how your type guards will behave with unexpected input types.

Examples

Example 1:

Input: { numDoors: 4 }
Output: "Processing a car with 4 doors."
Explanation: The input is a Car. The isCar type guard returns true, allowing access to numDoors.

Example 2:

Input: { hasBasket: true }
Output: "Processing a bicycle with a basket."
Explanation: The input is a Bicycle. The isBicycle type guard returns true, allowing access to hasBasket.

Example 3:

Input: { model: "Unknown" }
Output: "Unknown vehicle type."
Explanation: The input doesn't have numDoors or hasBasket. Both type guards return false, and the default case is executed.

Constraints

  • The solution must be written in TypeScript.
  • The code should be well-structured and readable.
  • The type guards must be accurate and efficient.
  • No external libraries are allowed.

Notes

  • The in operator is a common and effective way to implement type guards in TypeScript. It checks if a property exists on an object.
  • The typeof operator can also be used, especially when dealing with primitive types or checking for specific constructor functions.
  • Remember that type guards only narrow the type within a specific scope (e.g., inside an if statement). Outside that scope, the variable will still be of the union type.
  • Consider using discriminated unions for more complex scenarios. While not strictly required here, it's a good practice to be aware of.
Loading editor...
typescript