Type Predicate In Typescript Typescript

Feb 4th, 2022 - written by Kimserey with .

Type predicate in Typescript allows us to narrow down the type of a variable using a predicate. Today we’ll look at how to use type predicates, and show examples where they are useful.

Define Type Predicate

A type predicate takes the form of {variable} is {type} and is used on return type of functions.

1
2
3
4
5
6
7
8
9
10
11
12
13
interface Person {
  name: string;
}

interface House {
  address: string;
}

const values: (Person | House | string)[] = [
  { name: "Kim" },
  { address: "123 street" },
  "hello world",
];

In this example, we have two interfaces Person and House where the variable values is an array of a union between both and string.

Right after the declaration of values, the type will be (Person | House | string)[].

If we want to narrow down the type to either Person or House or string, we can create a function returning a type predicate.

1
2
3
function isPerson(value: Person | House): value is Person {
  return (value as Person).name !== undefined;
}

The type predicate value is Person informs the compiler that if the predicate (value as Person).name !== undefined returns true, value will be of type Person, else it will not be of type Person - meaning it will be of type House | string.

This construct is very useful as it allows the compiler to narrow down the type so that within the control statement, we are dealing with only the specific type.

Using the same isPerson predicate, we can define another predicate for isHouse:

1
2
3
function isHouse(value: Person | House | string): value is House {
  return (value as House).address !== undefined;
}

Then we can see that when using the predicates which return type predicates, we are able to indicate to the compiler the correct types we are dealing with:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
for (const v of values) {
  // v is `Person | House | string`

  if (isPerson(v)) {
    // v is `Person`
  } else {
    // v is `House | string`
    if (isHouse(v)) {
      // v is `House`
    } else {
      // v is `string`
    }
  }

  // v is `Person | House | string`
}

Use in Arrow Function

Type predicates can also be used in arrow functions to narrow down the type in array functions.

1
2
3
4
5
values
  .filter((v): v is Person => (v as Person).name !== undefined)
  .forEach((v) => {
    // v is `Person`
  });

And that concludes today’s post!

Conclusion

Today we looked at how we could use type predicate to narrow down types. We started by looking at how to define type predicate, we looked at how the type narrowing was finding the right types within the control flows. We then completed the post by looking at an example of type predicate used in arrow function. I hope you liked this post and I’ll see you on the next one!

Designed, built and maintained by Kimserey Lam.