WalzoneInterview Prep
📞 Interviewing soon? Practice with a realistic AI mock phone interview — it calls you, then scores you. First 15 min FREE →

TypeScript · Guru · question 94 of 100

Can you describe how to create custom type guards for complex types in TypeScript?

📕 Buy this interview preparation book: 100 TypeScript questions & answers — PDF + EPUB for $5

Custom type guards are functions that make it easier for TypeScript to identify the proper type of a variable during runtime. They can be especially useful when dealing with complex types made up of multiple interfaces or types, such as discriminated unions or intersection types.

Let’s go through the process of creating custom type guards step by step with an example.

Suppose we have a complex type that can be either a ‘Circle‘ or a ‘Rectangle‘, represented by the following interfaces:

interface Circle {
  kind: 'circle';
  radius: number;
}

interface Rectangle {
  kind: 'rectangle';
  width: number;
  height: number;
}

To define a custom type guard, you need a function that takes a parameter of a more general type (e.g., ‘unknown‘ or ‘any‘) and returns a boolean, with a ‘type predicate‘ as the return type. Here’s an example of a type guard for the ‘Circle‘ type:

function isCircle(shape: unknown): shape is Circle {
  return (shape as Circle).kind === 'circle';
}

In the example above, we’re taking an ‘unknown‘ parameter ‘shape‘ and use a type assertion to check whether its ‘kind‘ property is equal to ‘circle‘. If this condition is true, TypeScript can infer that the ‘shape‘ parameter is of type ‘Circle‘.

Following the same pattern, you can create a type guard for the ‘Rectangle‘ type:

function isRectangle(shape: unknown): shape is Rectangle {
  return (shape as Rectangle).kind === 'rectangle';
}

Now, let’s use our custom type guards with a function that calculates the area of a given shape:

type Shape = Circle | Rectangle;

function area(shape: Shape): number {
  if (isCircle(shape)) {
    return Math.PI * shape.radius * shape.radius;
  } else if (isRectangle(shape)) {
    return shape.width * shape.height;
  } else {
    throw new Error('Invalid shape type');
  }
}

In the ‘area‘ function, we make use of our custom type guards ‘isCircle‘ and ‘isRectangle‘ to check whether the input shape is a ‘Circle‘ or a ‘Rectangle‘. Once the type guard is confirmed by TypeScript, we have access to the specific properties of that type, like ‘radius‘, ‘width‘, and ‘height‘.

To summarize, custom type guards can be created by defining a function that takes a parameter of a general type and returns a boolean with a type predicate. These type guards greatly enhance TypeScript’s ability to infer types during runtime, particularly for complex types made up of multiple interfaces or other types.

Reading is step one. Saying it out loud is the interview. Our AI interviewer calls your phone and runs a realistic TypeScript interview — then scores it.
📞 Practice TypeScript — free 15 min
📕 Buy this interview preparation book: 100 TypeScript questions & answers — PDF + EPUB for $5

All 100 TypeScript questions · All topics