Learning Flow

Alasdair McLeay
3 min readMar 5, 2020

I recently came across the following flow type definition:

declare export type StyledShorthandFactory<V> = {|
[[call]]: <StyleProps, Theme>(
string[],
...Interpolation<PropsWithTheme<StyleProps, Theme>>[]
) => StyledComponent<StyleProps, Theme, V>,
[[call]]: <StyleProps, Theme>(
(props: PropsWithTheme<StyleProps, Theme>) => Interpolation<any>
) => StyledComponent<StyleProps, Theme, V>,
+attrs: <A: { ... }, StyleProps = {||}, Theme = {||}>(
(StyleProps => A) | A
) => TaggedTemplateLiteral<
PropsWithTheme<{| ...$Exact<StyleProps>, ...$Exact<A> |}, Theme>,
StyledComponent<
React$Config<{| ...$Exact<StyleProps>, ...$Exact<A> |}, $Exact<A>>,
Theme,
V
>
>,
|};

It has taken me a while to read and understand this, not least due to how hard it has been to navigate the flow documentation to find answers, so I’ve broken it down in to sections and put all the resources I used to understand it below.

Shortened example

Taking out the context specific types, and removing some repeated complexity, we end up with this shortened example:

declare export type MyType<T> = {|
[[call]]: <B>(D<B>) => C<B>,
[[call]]: <B>(string[], ...D<B>[]) => C<B, T>,
+property: <A: { ... }, B = {||}>((B => A) | A)
=> D<{| ...$Exact<B>, ...$Exact<A> |}, C<B, T>>,
|};

Declare export

type MyType<T>

Generics

{| property: value|}

Exact Object Types

[[call]]

This means that the object (interface?) being defined can also be called as a function. I think this is missing from the Flow documentation.

<B>() => C<B>

Function type with Generics

string[]

Array type shorthand syntax.

Also worth pointing out that this relates to Tagged Template Literals — a function that accepts an array of strings as its first parameter.

(…D<B>[]) => C<B>

The spread operator isn’t mentioned much in the flow documentation, but I am pretty sure this means a function that takes any number of parameters and all parameters must be of type D<B>.

A second [[call]] property

Can be called with different call signatures

+property

A read only interface property:

A: { … }

Explicit Inexact Object Type

TL;DR: A is an inexact object. It must be an object but can contain any properties.

A = {||}

Default A to an exact empty object.

{| …$Exact<B>, …$Exact<A> |}

This is slightly confusing as it uses 2 different syntaxes for the same utility:

{| name: string |} is the “Exact object type”:

$Exact<{name: string}> is a synonym for {| name: string |}

So by spreading the two exact object types, it creates a new exact object type containing the properties from A and B.

--

--