Learn TypeScript

Using a user-defined type guard with an assertion signature

Using a user-defined type guard with an assertion signature

In this lesson, we will learn what assertion signatures are and how we can use them in a user-defined type guard function.

Understanding an assertion signature

An assertion signature can be used in a function's return type to indicate the narrowed type of the parameter:

function assertTypeName(
paramName: WideTypeName
): asserts paramName is NarrowTypeName {
if (some_check) {
throw new Error("Assert failed");
}
}

asserts paramName is NarrowTypeName is the assertion signature in the above function.

The type guard function carries out some checks on its parameter and throws an error if it isn't the type being asserted. If no errors are raised, then TypeScript will narrow the type to the one being asserted.

An example

We are going to explore a user-defined type guard with an assertion signature in the TypeScript playground.

  • Open the TypeScript playground by clicking the link below:

https://www.typescriptlang.org/play

  • Set the version to 3.7 or beyond.

  • Copy the code from below into the TypeScript playground:

interface Person {
firstName: string;
surname: string;
}
interface Organisation {
name: string;
}
type Contact = Person | Organisation;
function sayHello(contact: Contact) {
// TODO - Output Hello {firstName} if a person
// TODO - Output Hello {name} if an organisation
}
const bob: Person = {
firstName: "Bob",
surname: "Young",
};
const redBricks: Organisation = {
name: "Red Bricks",
};
sayHello(bob);
sayHello(redBricks);

This code is the same we have been using in the last few lessons.

  • Let's create a user defined type guard to assert whether an object is a Person:
function assertIsPerson(contact: Contact): asserts contact is Person {
if ((contact as Person).firstName === undefined) {
throw new Error("Not a person");
}
}

The assertion signature is asserts contact is Person.

We are throwing an error if the firstName property is undefined. If the function returns without an error being raised, then the contact parameter is asserted to be of type Person.

  • In the sayHello function, output "Hello {firstName}" if the contact parameter is a Person using the assertIsPerson type guard:
function sayHello(contact: Contact) {
assertIsPerson(contact);
console.log("Hello " + contact.firstName);
}
🤔

What is the type of contact in the console.log statement?

Neat!

  • Create an assertion type guard, called assertIsOrganisation, to check whether an object is an Organisation.
  • Change the sayHello function implementation so that it outputs "Hello {name}" if the contact parameter is an Organisation. Remove the previous implementation for the Person type.
🤔

What is the type of contact in the console.log statement?

Nice!

Summary

A user-defined type guard can carry out checks on its parameter and use an assertion signature to tell TypeScript what type it is. A user-defined type guard that uses an assertion signature throws an error if the checks fail.

In the next lesson, we will learn about the discriminated union pattern.

© 2023 Carl Rippon
Privacy Policy
This site uses cookies. Click here to find out more