ApiaryActive
Try: pause · settings · learn · wipe
← Community / Reading Room
TT
typescript · 3 min read

typescript type guards

As a developer, you're probably familiar with the concept of type checking in TypeScript. It's a powerful tool that helps catch errors early on and makes your…

As a developer, you're probably familiar with the concept of type checking in TypeScript. It's a powerful tool that helps catch errors early on and makes your code more maintainable. However, sometimes you might find yourself needing to perform complex checks or transformations on your data, which can be cumbersome with traditional type guards.

In this article, we'll explore a lesser-known but incredibly useful feature of TypeScript: custom type guards. We'll also cover assertion functions and the in operator narrowing, and provide concrete examples to illustrate their usage.

Custom Type Guards

Custom type guards are functions that take an object as an argument and return a boolean value indicating whether the object conforms to a certain type. They're denoted by the isX suffix, where X is the name of the type you're checking against.

Let's create a simple example:

type Animal = { name: string; age: number };

function isDog(animal: Animal): animal is Dog {
  return 'name' in animal && typeof (animal as any).age === 'number';
}

interface Dog extends Animal {
  breed: string;
}

In this example, we define a isDog function that takes an Animal object and returns a boolean value indicating whether it's also a Dog. We use the in operator to check if the name property exists in the object, and then use the typeof operator to ensure that the age property is indeed a number.

Now let's see how we can use this custom type guard:

const animal: Animal = { name: 'Fido', age: 3, breed: 'Golden Retriever' };

if (isDog(animal)) {
  console.log(`My dog's name is ${animal.name} and he's a ${animal.breed}.`);
}

In this example, the isDog function narrows the type of animal to Dog, allowing us to access the breed property without any errors.

Assertion Functions

Assertion functions are similar to custom type guards but return a value instead of a boolean. They're often used in conjunction with the asserts keyword, which allows you to assert that an expression conforms to a certain type.

Let's create another example:

function assertsIsDog(animal: Animal): animal is Dog {
  if (!('name' in animal) || typeof (animal as any).age !== 'number') {
    throw new Error('Invalid dog');
  }
  return true;
}

const animal2 = { name: 'Fido', age: 3, breed: 'Golden Retriever' };

assertsIsDog(animal2);
console.log(`My dog's name is ${animal2.name} and he's a ${animal2.breed}.`);

In this example, we define an assertsIsDog function that takes an Animal object and returns a value indicating whether it conforms to the Dog type. We then use the asserts keyword to assert that animal2 is indeed a Dog.

in Operator Narrowing

The in operator can also be used for narrowing, as we saw earlier with custom type guards.

Let's create another example:

type Person = { name: string; age?: number };

const person1: Person = { name: 'John', age: 30 };
const person2: Person = { name: 'Jane' };

if ('age' in person1) {
  console.log(`Person ${person1.name} is ${person1.age} years old.`);
}

In this example, the in operator narrows the type of person1 to { name: string; age: number }, allowing us to access the age property without any errors.

When NOT to Use It

While custom type guards and assertion functions can be incredibly powerful tools, there are cases where they might not be the best choice. For instance:

  • If you're working with a large dataset or complex data structures, using custom type guards or assertion functions might lead to performance issues.
  • In some cases, using the in operator for narrowing might make your code harder to read or understand.

Related Apiary Lessons

If you want to learn more about advanced TypeScript features, be sure to check out our lessons on:

Conclusion

In this article, we explored the world of custom type guards, assertion functions, and the in operator narrowing. We saw how these features can be used to create powerful tools for working with complex data structures and types.

Remember, as a developer, it's essential to understand the nuances of TypeScript and its various features. With great power comes great responsibility!

And on that note, here's a bee-themed one-liner:

"A type guard is like a honeycomb cell – it holds everything together, but only when used correctly!"

Frequently asked
What is typescript type guards about?
As a developer, you're probably familiar with the concept of type checking in TypeScript. It's a powerful tool that helps catch errors early on and makes your…
What should you know about custom Type Guards?
Custom type guards are functions that take an object as an argument and return a boolean value indicating whether the object conforms to a certain type. They're denoted by the isX suffix, where X is the name of the type you're checking against.
What should you know about assertion Functions?
Assertion functions are similar to custom type guards but return a value instead of a boolean. They're often used in conjunction with the asserts keyword, which allows you to assert that an expression conforms to a certain type.
What should you know about in Operator Narrowing?
The in operator can also be used for narrowing, as we saw earlier with custom type guards.
What should you know about when NOT to Use It?
While custom type guards and assertion functions can be incredibly powerful tools, there are cases where they might not be the best choice. For instance:
References & sources
  1. Apiary Reading RoomOpen, cited knowledge base — funded to keep bee & practical research free.
From the Apiary Reading Room. Opinion & editorial — not financial advice. We don't overclaim.
More from the Reading Room