developer's blog by 

Notes on Flow 0.100

June 12, 2019

Flow 0.100 is out 💯. Reading and learning about Flow and JavaScript as always. This time, I have a short note on object destructuring, React type definitions, and put a link to a nice article explaining variance sigils.

Flow 0.100 has very nice release notes with examples. So I won’t repeat what is already said there. Here are some bullet points I jotted down as I tried to learn about the changes.


Destructuring objects in function parameters

Destructuring patterns could previously include missing properties if the resulting binding was unused. This is now an error even when unused. Try Flow example

type O = { p: string }
// Error: There is no property `q` in type `O`, as of Flow v0.100.0
function f({ p, q }: O) {}

One confusion I encountered was this

Does it mean all object will be exact?

So I took this chance to clarify some of the things around here. Exact means the object passed in here must not contain extra fields (link to doc).

Sealed, on the other hand, means the object may contain other fields but you may not access them unless you annotate them. When we write an object type with some fields, it is by default sealed. Trying to access unannotated field of a sealed object will result in error, regardless of it being exact or not:

type Sealed = { foo: string }

const sealed = {
  foo: 'foo',
}
sealed.bar = 'bar' // error
const { foo, bar } = sealed // error

For functions that expect sealed objects, you can still pass in objects with extra props.

function usingSealed(x: Sealed) {
  // does things
}
usingSealed({ foo: 'foo', bar: 'bar' }) // ok

Not so when the functions are expecting exact objects:

type Exact = {| foo: string |}

function usingExact(x: Exact) {
  // does things
}
usingExact({ foo: 'foo', bar: 'bar' }) // error

We may access the fields of function parameters by destructuring the object:

// destructuring on function parameter
function goodUsingSealed({ foo }: Sealed) { // ok
  // does things
}

But since destructuring means accessing the object, we should not be able to access extra props to sealed objects. This is fixed in 0.100:

// fixed in 0.100
function badUsingSealed({ foo, bar }: Sealed) { // error after 0.100
  // does things
}

React component types

There are a bunch of changes around React library definitions. And so it’s a good chance to take a step back and look at what they are in all.

Here is the link to the React library definitions by Flow.

My list of commonly used:

  • React$Component<Props, State = void>
  • AbstractComponent<-Config, +Instance = mixed>
  • React$ComponentType<-Config>
  • React$ElementType
  • React$Element<+ElementType: React$ElementType>
  • (new) React$MixedElement = React$Element<React$ElementType>
  • (new) MixedElement = React$MixedElement
  • React$Ref<ElementType: React$ElementType>

In the definitions above, those with the angled brackets are polymorphic types. This means you’ll need to supply type parameters for those polymorphics.

React$Component<Props, State = void>

React$Component is the base class of ES6 React classes, modeled as a polymorphic class whose main type parameters are Props and State.

React$AbstractComponent

React$AbstractComponent is the type name used by Flow, and is used by a few different types of React classes and components in React’s library declarations.

React.AbstractComponent uses it directly, which takes two parameters, Config for the props type, and Instance for an instance. Functional components have Instance: void.

React$ComponentType

declare type React$ComponentType<-Config> = React$AbstractComponent<
  Config,
  mixed
>

Aliased to React$AbstractComponent<Config, mixed>, and is used as the type of a component in React. It can be:

  • Stateless functional components. Functions that take in props as an argument and return a React node.
  • ES6 class component. Components with state defined either using the ES6 class syntax, or with the legacy React.createClass() helper.

React$ElementType

declare type React$ElementType = string | React$AbstractComponent<empty, mixed>

The type of an element in React. A React element may be a:

  • string: These elements are intrinsics that depend on the React renderer implementation.
  • React component. See ComponentType for more information about its different variants.

A few more related with ElementType:

A React$Element is the type of a React element. React elements are commonly created using JSX literals, which desugar to React.createElement calls (see below).

declare type React$Element<+ElementType: React$ElementType> = {|
  +type: ElementType,
  +props: React$ElementProps<ElementType>,
  +key: React$Key | null,
  +ref: any,
|}

Finally, here are the two new types:

declare type React$MixedElement = React$Element<React$ElementType>
declare type MixedElement = React$MixedElement

A keen reader may have noticed that above is more or less a copy and paste of comments and code snippets from Flow’s codebase. They are really very well-written and a significant portion of the code itself is self-explanatory.


Variance sigils

Variance sigils are everywhere in library definitions. If this set of synonyms works for you, feel free to think of covariance as read-only, and contravariance as write-only.

This article Flow’s Best Kept Secret explains it very well.

🐶 Till next time

Flow 0.101 is already out and I’m falling behind 😭 It’s JSConf.Asia at home now. Gonna chill down a bit next week and get back to my normal Flow :]