Flow is a type checker made by Facebook for checking JavaScript data types. It has many built-in data types we can use to annotate the types of variables and function parameters.
In this article, we’ll look at how to cast values from one type to another.
Syntax
To value to a given type, we can use the following syntax:
(value: Type)
It can be used in variables, objects, or arrays. In variable assignments, it can be used as follows:
let foo = (value: Type);
With objects, we can cast the values of properties by writing:
let obj = { prop: (value: Type) };
Also, we can cast array entries by writing:
let arr = ([(value: Type), (value: Type)]: Array<Type>);
We can also cast expressions into a type. For example, we can write:
(1 + 1: number);
to cast numbers.
Type Assertions
We can only cast types when they make sense. For example, if we have:
let x = 1;
Then we can write:
(x: 1);
or:
(x: number);
since x
is a number with value 1
. Casting to a type that isn’t the type of the value will fail. So casting the variable x
to s string by writing:
(x: string)
will give an error since x
is a number.
Type Casting
We can cast a value to a broader type than the original type of a variable. For example, if we have a number variable:
let x = 1;
Then we can either cast x
to the 1
literal type or the number
type as follows:
(x: 1);
(x: number);
When we assign a variable to a new variable, we can also cast it to the same broad type:
let y = (x: number);
But casting it to a narrower type will fail, so if we write:
(y: 1);
we would get an error since y
is expected to be a number
with an indeterminate value.
Type Casting Through any
We can cast anything to any
, which then let us cast it to anything else.
For example, if we want to cast a number into a string, we can see that we can’t do it directly from the examples above since we can’t cast anything to an unrelated type.
However, we can bypass that by first casting to any
, then we can cast it to any type we want.
So we can write:
let x = 1;
(x: 1);
(x: number);
let y = ((x: any): string);
(y: string);
This isn’t recommended, but it may be convenient for some situations where we need to cast something from one type to an unrelated type.
Type Assertions
We can set the type of an object by casting the type of the object when we operate on it in a function. For example, if we have a function that clones an object, we can write:
function foo(obj) {
const cloneObj = {...(obj: { [key: string]: mixed })};
return cloneObj;
}
Then when we call it, Flow is smart enough to determine the type of the properties:
let cloneObj = foo({
a: 1,
b: true,
c: 'three'
})
(cloneObj.a: 1);
(cloneObj.b: true);
(cloneObj.c: 'three');
This is more useful than putting the type in the parameter:
function foo(obj: { [key: string]: mixed }) {
const cloneObj = {...obj};
return cloneObj;
}
Since Flow won’t know the structure of cloneObj
this way.
We can also use generics with the $Shape
keyword to assert the type of the obj
parameter as follows:
function foo<T: { [key: string]: mixed }>(obj: T): $Shape<T> {
const cloneObj = {...obj};
return cloneObj;
}
The code<T: { [key: string]: mixed }>
will let Flow know that the obj
parameter accepts an object.
With Flow, we can cast types to relevant types given the object’s value by using the :
and the type identifier after it.
Also, we can cast something to an unrelated type by first casting it to any
.
Finally, to make Flow be aware that a variable or parameter is a dynamic object, we can use the <T: { [key: string]: mixed }>
and (obj: T)
signature to make sure that the parameter is a dynamic object.
Then we set $Shape<T>
as the return type to enforce that type of the object returned by the function is a dynamic object.