Type Casting Expressions
Type cast expressions let you widen or assert a value's type inline using the as keyword.
const x = 42 as number;
Flow's as only widens or asserts, while TypeScript's as permits unsafe downcasts that invent properties. The cast {foo: 1} as {foo: number, bar: string} type-checks in TypeScript (asserting a non-existent bar) but errors in Flow. See as casts are safer in Flow for the full comparison.
When to use this
Use casts to widen a value to a less specific type or to verify that a value matches an expected type at a specific point in your code. For narrowing a value to a more specific type, prefer refinements or type guards — casting through any is unsafe and should be a last resort.
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".
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:
2 + 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:
1 === 1 as boolean; // Error! // Above same as `1 === (1 as boolean) (1 === 1) as boolean; // Works!
Additionally, when in the context of an expression statement, expressions which could ambiguously parse as statements need parens:
({a: 1}) as {a: number}; // Needs parens to disambiguate from block statement
const 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.
const value = 42; value as 42; // Works! value as number; // Works! value as string; // Error!
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.
const value = 42; value as 42; // Works! value as number; // Works! let newValue = value as number; newValue as 42; // Error! newValue as number; // Works!
Unsafe downcasts are not allowed:
const fooObj = {foo: 1};
const otherObj = fooObj as {foo: number, bar: string}; // ERROR Adoption of as syntax
To use the as keyword for type casts, you need to upgrade your infrastructure so that it supports the syntax:
- Prettier: 3.1+
- Babel: use flow-parser/babel-plugin, see our Babel guide for more details.
- ESLint: use flow-eslint, see our ESLint guide for more details.
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.
let value = 42; value as number; // Works! value as string; // Error! let newValue = value as any as string; newValue as number; // Error! newValue as string; // Works!
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.
function cloneObject(obj: any) {
const clone: {[string]: unknown} = {};
Object.keys(obj).forEach(key => {
clone[key] = obj[key];
});
return clone;
} 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.
function cloneObject<T extends {readonly [key: string]: unknown }>(obj: T): T {
const clone: {[string]: unknown} = {};
Object.keys(obj).forEach(key => {
clone[key] = obj[key];
});
return clone as any as T;
}
const clone = cloneObject({
foo: 1,
bar: true,
baz: 'three'
});
clone.foo as number; // Works!
clone.bar as boolean; // Works!
clone.baz as string; // Works! See Also
- Refinements — prefer narrowing types via conditional checks over casting
- Type Guards — custom refinement functions as a safe alternative to casting
-
Any — casting through
anyfor unsafe type conversions (last resort) - Subtypes — understanding which casts are allowed based on subtyping rules
-
Const Expressions —
as constfor narrowing to literal and read-only types -
Modernizing Legacy Flow Syntax — migrating legacy
(x: T)colon casts to theassyntax
© 2013–present Facebook Inc.
Licensed under the MIT License.
https://flow.org/en/docs/types/casting