Skip to main content

Type Casting Expressions

Sometimes it is useful to assert a type without using something like a function or a variable to do so. For this Flow supports an inline type cast expression syntax which can be used in a number of different ways.

Type Cast Expression Syntax

In order to create a type cast expression, use the keyword as to cast the value to a type:

value as Type

This can also be referred to as an "as expression".

Before Flow version 0.229, the legacy syntax (value: Type) was used.

Type cast expressions can appear anywhere an expression can appear:

let val = value as Type;
let obj = {prop: value as Type};
let arr = [value as Type, value as Type] as Array<Type>;

The value itself can also be an expression:

12 + 2 as number;

Note that the as operator has the same precedence as in and instanceof. Because of this, parentheses around the expression might be required:

11 === 1 as boolean; // Error!
2// Above same as `1 === (1 as boolean)3 4(1 === 1) as boolean; // Works!
1:7-1:7: Cannot cast `1` to boolean because number [1] is incompatible with boolean [2]. [incompatible-cast]

Additionally, when in the context of an expression statement, expressions which could ambiguously parse as statements need parens:

1({a: 1}) as {a: number}; // Needs parens to disambiguate from block statement2const x = {a: 1} as {a: number}; // No parens needed, as not in expression statement context

When you strip the types all that is left is the value:

value as Type;

Is transformed into:

value;

Type Assertions

Using type cast expressions you can assert that values are certain types.

1let value = 42;2
3value as 42;     // Works!4value as number; // Works!5value as string; // Error!
5:1-5:5: Cannot cast `value` to string because number [1] is incompatible with string [2]. [incompatible-cast]

Asserting types in this way works the same as types do anywhere else.

Type Casting

When you write a type cast expression, the result of that expression is the value with the provided type. If you hold onto the resulting value, it will have the new type.

1let value = 42;2
3value as 42;     // Works!4value as number; // Works!5
6let newValue = value as number;7
8newValue as 42;     // Error!
9newValue as number; // Works!
8:1-8:8: Cannot cast `newValue` to number literal `42` because number [1] is incompatible with number literal `42` [2]. [incompatible-cast]

Unsafe downcasts are not allowed:

1const fooObj = {foo: 1};2const otherObj = fooObj as {foo: number, bar: string};  // ERROR
2:18-2:23: Cannot cast `fooObj` to object type because property `bar` is missing in object literal [1] but exists in object type [2]. [prop-missing]

Adoption of as syntax

To use the as keyword for type casts, you need to upgrade your infrastructure so that it supports the syntax:

For more details on how to migrate to the new casting syntax (as) check out our blog post.

Using type cast expressions

Note: We're going to go through a stripped down example for demonstrating how to make use of type cast expressions. This example is not solved well in practice.

Type Casting through any

Because type casts work the same as all other type annotations, you can only cast values to less specific types. You cannot change the type or make it something more specific.

But you can use any to cast to whatever type you want.

1let value = 42;2
3value as number; // Works!4value as string; // Error!
5 6let newValue = value as any as string;7 8newValue as number; // Error!
9newValue as string; // Works!
4:1-4:5: Cannot cast `value` to string because number [1] is incompatible with string [2]. [incompatible-cast]
8:1-8:8: Cannot cast `newValue` to number because string [1] is incompatible with number [2]. [incompatible-cast]

By casting the value to any, you can then cast to whatever you want.

This is unsafe and not recommended. But it's sometimes useful when you are doing something with a value which is very difficult or impossible to type and want to make sure that the result has the desired type.

For example, the following function for cloning an object.

1function cloneObject(obj: any) {2  const clone: {[string]: mixed} = {};3
4  Object.keys(obj).forEach(key => {5    clone[key] = obj[key];6  });7
8  return clone;9}

It would be hard to create a type for this because we're creating a new object based on another object.

If we cast through any, we can return a type which is more useful.

1function cloneObject<T: {+[key: string]: mixed }>(obj: T): T {2  const clone: {[string]: mixed} = {};3
4  Object.keys(obj).forEach(key => {5    clone[key] = obj[key];6  });7
8  return clone as any as T;9}10
11const clone = cloneObject({12  foo: 1,13  bar: true,14  baz: 'three'15});16
17clone.foo as 1;       // Works!18clone.bar as true;    // Works!19clone.baz as 'three'; // Works!

Legacy casting syntax

Before version 0.229, to create a type cast expression around a value, you would add a colon : with the Type and wrap the expression with parentheses ( ).

(value: Type)

Note: The parentheses are necessary to avoid ambiguity with other syntax.