ProgrammingFrontend Developer

Describe the type guard mechanism in TypeScript and provide examples of its use. What is the main advantage and what nuances should be considered when implementing custom type guard functions?

Pass interviews with Hintsage AI assistant

Answer.

Type Guards are mechanisms that allow you to refine the type of a variable within a code block based on some checks (for example, using typeof, instanceof, or special functions returning expressions of the form param is SomeType).

Main advantage — is safety and the elimination of runtime errors through type checking at compile-time.

Example:

interface Fish { swim: () => void } interface Bird { fly: () => void } function isFish(pet: Fish | Bird): pet is Fish { return (pet as Fish).swim !== undefined; } function move(pet: Fish | Bird) { if (isFish(pet)) { pet.swim(); } else { pet.fly(); } }

Here, the function isFish is a custom type guard.

Nuances:

  • Any additional logical checks must be strictly related to typing.
  • Errors in type guard functions can lead to incorrect type definitions at runtime.

Trick Question.

Question: "Will the TypeScript compiler always rely only on the returned value of the guard function, or does it use some other analysis inside the function?"

Answer: The TypeScript compiler relies solely on the signature of the returned value param is Type. What happens inside the guard function is not analyzed for correctness of implementation.

Example (dangerous error!):

function isString(x: any): x is string { return true; } // The compiler will assume it’s always a string, although this is not the case: if (isString(123)) { // here x is of type string, but in fact it is a number }

Examples of real errors due to lack of knowledge of the subtleties of the topic.


Story

In a project with shared DTOs between the front-end and backend, a strict check was forgotten inside the custom type guard. As a result, some data was incorrectly perceived as the required type, leading to client-side crashes when trying to use a missing property.


Story

A developer wrote a type guard relying on an optional field, but the data structure allowed for that field to be completely absent. As a result, the type switch-case lacked a branch, and the compiler did not issue warnings — exceptions arose at runtime.


Story

In one of the services, when transitioning to TypeScript, they relied solely on built-in type guards (typeof, instanceof). When the prototype of objects changed during execution, the checks became incorrect, causing hard-to-debug bugs in production.