# Type Guards

Flow lets you define functions whose return expression encodes some type predicate over a parameter `param`

. This predicate is annotated in place of a return type annotation as `param is PredicateType`

. It declares that if the function returns `true`

then `param`

is of type `PredicateType`

.

The syntax for a function like this is:

`function predicate(param: InputType): param is PredicateType {`

return <some_expression>;

}

The type of this function can also be written in terms of a type guard annotation:

`type PredicateFunc = (param: InputType) => param is PredicateType;`

## Basic Usage

Let's see a simple example where we define a type guard function and then use it to refine some values.

### Defining a type guard function

```
1type A = { type: "A"; data: string };2type B = { type: "B"; data: number };3type AorB = A | B;4
5function isA(value: AorB): value is A {6 return value.type === "A";7}
```

We have defined a data type `AorB`

that is a disjoint union of two types `A`

and `B`

that each have a property `type`

used as tag.

We have also written a *user defined type guard* function `isA`

defined over objects of type `AorB`

. This function returns `true`

when the value of of the `type`

property of its input is `"A"`

. Using the definitions of `A`

and `B`

, Flow can prove that when the value of `type`

is `"A"`

then the type of `value`

will be `A`

.

### Using a type guard function to refine values

Functions that have a declared type guard can be used to refine values in conditionals. In the example above, we can use `isA`

to refine a variable of type `AorB`

to just `A`

:

```
1type A = { type: "A"; data: string };2type B = { type: "B"; data: number };3type AorB = A | B;4
5function isA(value: AorB): value is A {6 return value.type === "A";7}8
9function test(x: AorB) {10 if (isA(x)) {11 // `x` has now been refined to type A.12 // We can assign it variables of type A ...13 const y: A = x;14 // ...and access A's properties through `x`15 const stringData: string = x.data;16
17 // As a sanity check, the following assignment to B will error18 const error: B = x; 19 }20}
```

18:22-18:22: Cannot assign `x` to `error` because string [1] is incompatible with number [2] in property `data`. [incompatible-type]18:22-18:22: Cannot assign `x` to `error` because string literal `A` [1] is incompatible with string literal `B` [2] in property `type`. [incompatible-type]

In the then-branch of the conditional `if (isA(x))`

, `x`

will have the type `A`

.

### One-sided Type Guards

**Note:** This feature is available as of v0.237.0 when option `one_sided_type_guards=true`

is set in the flowconfig. It is enabled by default as of v0.239.0.

In some cases we may want to declare that a type guard function only refines the then-branch of a conditional. Consider for example the function

`1function isPositive(n: ?number): boolean {2 return n != null && n > 0;3}`

If we declared `n is number`

as the type guard of this function then in the following code:

`declare n: ?number;`

if (isPositive(n)) {

// n is number here

} else {

// n would be null | void here

}

we would be able to establish that `n`

is `null | void`

in the else-branch. This is not true, however, since `n`

could just be a non-negative number.

One-sided type guards, which we annotate as `implies param is PredicateType`

, let us specify that a predicate narrows the type in only the positive case. For example,

`1function isPositive(n: ?number): implies n is number {2 return n != null && n > 0;3}`

Now, we'll get the following behavior

`declare n: ?number;`

if (isPositive(n)) {

// n is number here

} else {

// n is still ?number

}

## Refine with `Array.filter`

Flow recognizes when you call `filter`

on an array of type `Array<T>`

with a callback function that holds a type guard with type `(value: T) => value is S`

.
It will use this to produce an output array of type `Array<S>`

. Note that `S`

needs to be a subtype of the type of the array element `T`

.

For example

```
1type Success = $ReadOnly<{type: 'success', value: 23}>;2type Error = $ReadOnly<{type: 'error', error: string}>;3
4type Response =5 | Success6 | Error7
8function filterSuccess(response: Array<Response>): Array<Success> {9 return response.filter(10 (response): response is Success => response.type === 'success'11 );12}13
14function filterError1(response: Array<Response>): Array<Error> {15 const result = response.filter(16 (response): response is Success => response.type === 'success'17 );18 // The following is expected to error19 return result; 20}21
22function filterError2(response: Array<Response>): Array<Error> {23 const result = response.filter(24 // The following is expected to error25 (response): response is Error => response.type === 'success' 26 );27 return result;28}
```

19:10-19:15: Cannot return `result` because property `error` is missing in object type [1] but exists in object type [2] in array element. [prop-missing]19:10-19:15: Cannot return `result` because property `value` is missing in object type [1] but exists in object type [2] in array element. [prop-missing]19:10-19:15: Cannot return `result` because string literal `success` [1] is incompatible with string literal `error` [2] in property `type` of array element. [incompatible-return]25:17-25:33: Inconsistent type guard declaration because property `error` is missing in object type [1] but exists in object type [2]. The type of `response` [3] refined with the predicate encoded in return expression `response.type === 'success'` [4] needs to be compatible with the guard type `Error` [2]. See 1. in https://flow.org/en/docs/types/type-guards/#toc-consistency-checks-of-type-guard-functions. [prop-missing]25:17-25:33: Inconsistent type guard declaration because string literal `success` [1] is incompatible with string literal `error` [2] in property `type`. The type of `response` [3] refined with the predicate encoded in return expression `response.type === 'success'` [4] needs to be compatible with the guard type `Error` [5]. See 1. in https://flow.org/en/docs/types/type-guards/#toc-consistency-checks-of-type-guard-functions. [incompatible-type-guard]25:29-25:33: Inconsistent type guard declaration because property `value` is missing in object type [1] but exists in object type [2]. The type of `response` [3] refined with the predicate encoded in return expression `response.type === 'success'` [4] needs to be compatible with the guard type `Error` [1]. See 1. in https://flow.org/en/docs/types/type-guards/#toc-consistency-checks-of-type-guard-functions. [prop-missing]25:17-25:33: Inconsistent type guard declaration. The negation of the predicate encoded in return expression `response.type === 'success'` [1] needs to completely refine away the guard type `Error` [2]. Consider using a one-sided type-guard (`implies x is T`). See 2. in https://flow.org/en/docs/types/type-guards/#toc-consistency-checks-of-type-guard-functions. [incompatible-type-guard]

In `filterError1`

, filtering produces `Array<Success>`

that is not compatible with the expected return type `Array<Error>`

.

In `filterError2`

, the predicate `response.type === 'success'`

is used to refine `Response`

s to `Success`

s, not `Error`

s.

## Defining Type Guard Functions

To ensure that refinement with type guard functions is sound, Flow runs a number of checks associated with these functions.

### Predicate parameter is a regular parameter to the function

In a type guard annotation of the form `parameter is Type`

, `parameter`

needs to belong to the current function's parameter list.

`1function missing(param: mixed): prop is number { 2 return typeof param === "number";3}`

1:33-1:36: Cannot find type guard parameter `prop` [1] in the parameters of this function (type). [function-predicate]

It cannot be a parameter bound in a destructuring pattern, or a rest paramter:

`1function destructuring({prop}: {prop: mixed}): prop is number { 2 return typeof prop === "number";3}`

1:48-1:51: A type guard parameter `prop` [1] cannot reference pattern parameter `prop` [2]. [function-predicate]

`1function rest(...value: Array<mixed>): value is Array<mixed> { 2 return Array.isArray(value);3}`

1:40-1:44: A type guard parameter `value` [1] cannot reference rest parameter `value` [2]. [function-predicate]

### Predicate type is consistent with the parameter type

The type guard `Type`

needs to be compatible with the type of the parameter. In other words, given a definition

`function isT(x: ParamType): x is Type {`

return ...

}

Flow will check that `Type`

is a subtype of `ParamType`

. So the following will be an error:

`1function isNumber(x: string): x is number { 2 return typeof x === "number";3}`

1:36-1:41: Cannot use number [1] as type prediate for parameter `x` because number [1] is incompatible with string [2]. A user defined type guard needs to be compatible with its parameter's type. [incompatible-type-guard]

### Type guard function returns boolean

A type guard function needs to return a boolean expression. The following are invalid declarations:

`1function isNumberNoReturn(x: string): x is string {} `

1:39-1:49: Cannot declare a type predicate [1] for function [2] because boolean [1] is incompatible with implicitly-returned undefined. [incompatible-return]

`1function nonMaybe<V: {...}>(x: ?V): x is V {2 return x; 3}`

2:10-2:10: Cannot return `x` because null or undefined [1] is incompatible with boolean [2]. [incompatible-return]2:10-2:10: Cannot return `x` because object type [1] is incompatible with boolean [2]. [incompatible-return]

A correct version of `nonMaybe`

would be

`1function nonMaybe<V: {...}>(x: ?V): x is V {2 return !!x;3}`

### Predicate type is consistent with refined type

In addition to the above checks, Flow also ensures that the declared type guard is consistent with the check happening in the body of the function. To establish this it needs to guarantee two things:

- The type of the refined parameter at the return location
*after*the predicate of the return expression has been applied is a subtype of the guard type. For example, the following definitions are correct:

```
1function numOrStr(x: mixed): x is number | string {2 return (typeof x === "number" || typeof x === "string");3}4
5function numOrStrWithException(x: mixed): x is number | string { 6 if (typeof x === "number") {7 return true;8 } else {9 if (typeof x === "string") {10 return true;11 } else {12 throw new Error("");13 }14 }15}
```

5:43-5:62: Inconsistent type guard declaration. The negation of the predicate encoded in return expression `true` [1] needs to completely refine away the guard type union type [2]. Consider using a one-sided type-guard (`implies x is T`). See 2. in https://flow.org/en/docs/types/type-guards/#toc-consistency-checks-of-type-guard-functions. [incompatible-type-guard]5:43-5:62: Inconsistent type guard declaration. The negation of the predicate encoded in return expression `true` [1] needs to completely refine away the guard type union type [2]. Consider using a one-sided type-guard (`implies x is T`). See 2. in https://flow.org/en/docs/types/type-guards/#toc-consistency-checks-of-type-guard-functions. [incompatible-type-guard]

But in the following Flow will raise errors:

`1function numOrStrError(x: mixed): x is number | string { 2 return (typeof x === "number" || typeof x === "boolean");3}`

1:35-1:54: Inconsistent type guard declaration because: [incompatible-type-guard] Either boolean [1] is incompatible with number [2]. Or boolean [1] is incompatible with string [3]. The type of `x` [4] refined with the predicate encoded in return expression `((typeof x) === "number") || ((typeof x) === "boolean")` [5] needs to be compatible with the guard type union type [6]. See 1. in https://flow.org/en/docs/types/type-guards/#toc-consistency-checks-of-type-guard-functions.1:35-1:54: Inconsistent type guard declaration. The negation of the predicate encoded in return expression `((typeof x) === "number") || ((typeof x) === "boolean")` [1] needs to completely refine away the guard type union type [2]. Consider using a one-sided type-guard (`implies x is T`). See 2. in https://flow.org/en/docs/types/type-guards/#toc-consistency-checks-of-type-guard-functions. [incompatible-type-guard]

- Type guard functions can be used to refine the else-branch of conditionals. For example,

```
1function isNumber(x: mixed): x is number {2 return typeof x === "number";3}4
5declare var value: number | string;6if (isNumber(value)) {7 value as number; // okay8} else {9 value as string; // also okay10}
```

Therefore, the inverse form of the first requirement also needs to hold. Specifically, if we negate the predicate encoded in the function, and use it to refine the input, then the result must not overlap with the type guard at all. This condition is equivalent to checking that the type guard refined with the negation of the function predicate is a subtype of `empty`

. For example the following raises an error:

`1function isPosNum(x: mixed): x is number { 2 return typeof x === 'number' && x > 0;3}`

1:30-1:40: Inconsistent type guard declaration. The negation of the predicate encoded in return expression `((typeof x) === 'number') && (x > 0)` [1] needs to completely refine away the guard type number [2]. Consider using a one-sided type-guard (`implies x is T`). See 2. in https://flow.org/en/docs/types/type-guards/#toc-consistency-checks-of-type-guard-functions. [incompatible-type-guard]

This is because the negation of the predicate of `isPosNum`

is "`x`

is not a number or `x<=0`

". This predicate is equivalent to the empty predicate and does not refine the input type it is applied to.

If you're seeing errors related to this check, consider using a one-sided type guard (write `implies x is T`

). Ones-sided type guards do not require this check, since they do not refine the else-branch of conditionals.

**Note:** This check only happens when `one_sided_type_guards=true`

is set in the flowconfig. It happens by default as of v0.239.0.

- The parameter that is refined cannot be reassigned in the body of the type guard function. Therefore the following are errors:

`1function isNumberError1(x: mixed): x is number {2 x = 1;3 return typeof x === "number"; 4}`

3:10-3:30: Cannot use type guard parameter `x` [1] because at this return point it is written to in [2]. [function-predicate]

`1function isNumberError2(x: mixed): x is number { 2 function foo() {3 x = 1;4 }5 foo();6 return typeof x === "number";7}`

1:36-1:36: Cannot use type guard parameter `x`, because `x` [1] is reassigned in [2]. [function-predicate]

## Adoption

To use type guards, you need to upgrade your infrastructure so that it supports the syntax:

`flow`

and`flow-parser`

: 0.209.1. Between v0.209.1 to v0.211.1, you need to explicitly enable it in your .flowconfig, under the`[options]`

heading, add`type_guards=true`

. One-sided type guards are available as of version 0.237.0 with the option`one_sided_type_guards=true`

, and are enabled by default as of v0.239.0.`prettier`

: 3`babel`

with`babel-plugin-syntax-hermes-parser`

. See our Babel guide for setup instructions.`eslint`

with`hermes-eslint`

. See our ESLint guide for setup instructions.