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 piece, we’ll look at how to use intersection types to create variables that accept a combination of multiple types.
Defining Intersection Types
We can create intersection types by separating multiple types with an &
sign as follows:
Type1 & Type2 & ... & TypeN
We can also break the expression above into multiple lines with the leading &
sign:
type Bar =
& Type1
& Type2
& ...
& TypeN
Also, we can create intersection types from other intersection types:
type A = Type1 & Type2;
type B = Type3 & Type4;
type Foo = A & B;
Properties of Intersection Types
When we call a function that accepts an intersection type, we must pass in data that has all of those types. But inside the function, we can treat them as being one of the types in the intersection type.
For example, if we define the following function:
type A = { a: number };
type B = { b: boolean };
type C = { c: string };
function foo(value: A & B & C) {
}
Then we can treat value
as having to be any one of A
, B
and C
, as follows:
function foo(value: A & B & C) {
let a: A = value;
let b: B = value;
let c: C = value;
}
Impossible Intersection Types
We can create intersection types that are impossible. For example, we can create a type that’s an intersection of string
and boolean
, as follows:
type StringBoolean = string & boolean;
This type is useless since no value can be both a string and a boolean, so we can’t assign anything to it.
Intersections of Object Types
An intersection of object types means that an object of the intersection type must have all the properties of both types.
For example, suppose we have the following intersection type:
type Foo = { foo: string };
type Bar = { bar: boolean };
type FooBar = Foo & Bar;
The variable that we create of type FooBar
must have all the properties of both Foo
and Bar
:
let foobar : FooBar = {
foo: 'abc',
bar: true
};
When two object types have the same property name but a different type, then when they’re intersected together, the new property with the same name will have the intersection of both types as the new type.
For example, suppose we have:
type Foo = { foo: string };
type Bar = { foo: boolean };
type FooBar = Foo & Bar;
Then foo
will have the string & boolean
intersection type, which means that no value can be set to it.
With intersection types, we can create types that have all the properties of each type that form the intersection type. We can also create intersection types from primitive types, but they’re useless since nothing can be assigned to variables of those types.
This means that intersection types are useful for object types mostly.