Version 0.21.0

February 2, 2016 by Gabe Levi

Yesterday we deployed Flow v0.21.0! As always, we’ve listed out the most interesting changes in the Changelog. However, since I’m on a plane and can’t sleep, I thought it might be fun to dive into a couple of the changes! Hope this blog post turns out interesting and legible!

JSX Intrinsics#

If you’re writing JSX, it’s probably a mix of your own React Components and some intrinsics. For example, you might write

render() {
  return <div><FluffyBunny name="Fifi" /></div>;
}

In this example, FluffyBunny is a React Component you wrote and div is a JSX intrinsic. Lower-cased JSX elements are assumed to be intrinsics by React and by Flow. Up until Flow v0.21.0, Flow ignored intrinsics and gave them the type any. This meant Flow let you set any property on JSX intrinsics. Flow v0.21.0 will, by default, do the same thing as v0.20.0, However now you can also configure Flow to properly type your JSX intrinsics!

Example of how to use JSX intrinsics#

.flowconfig

[libs]
myLib.js

myLib.js

// JSXHelper is a type alias to make this example more concise.
// There's nothing special or magic here.
// JSXHelper<{name: string}> is a React component
// with the single string property "name", which has a default
type JSXHelper<T> = Class<ReactComponent<T,T,mixed>>;

// $JSXIntrinsics is special and magic.
// This declares the types for `div` and `span`
type $JSXIntrinsics = {
  div: JSXHelper<{id: string}>,
  span: JSXHelper<{id: string, class: string}>,
};

myCode.js

<div id="asdf" />; // No error
<div id={42} />; // Error: `id` prop is a string, not a number!

What is going on here?#

The new bit of magic is this $JSXIntrinsics type alias. When Flow sees <foo /> it will look to see if $JSXIntrinsics exists and if so will grab the type of $JSXIntrinsics['foo']. It will use this type to figure out which properties are available and need to be set.

We haven’t hardcoded the intrinsics into Flow since the available intrinsics will depend on your environment. For example, React native would have different intrinsics than React for the web would.

Smarter string refinements#

One of the main ways that we make Flow smarter is by teaching it to recognize more ways that JavaScript programmers refine types. Here’s an example of a common way to refine nullable values:

class Person {
  name: ?string;
  ...
  getName(): string {
    // Before the if, this.name could be null, undefined, or a string
    if (this.name != null) {
      // But now the programmer has refined this.name to definitely be a string
      return this.name;
    }
    // And now we know that this.name is null or undefined.
    return 'You know who';
  }
}

New string refinements#

In v0.21.0, one of the refinements we added is the ability to refine types by comparing them to strings.

This is useful for refining unions of string literals into string literals

function test(x: 'foo' | 'bar'): 'foo' {
  if (x === 'foo') {
    // Now Flow understands that x has the type 'foo'
    return x;
  } else {
    return 'foo';
  }
}

And can also narrow the value of strings:

function test(x: string): 'foo' {
  if (x === 'foo') {
    // Now Flow knows x has the type 'foo'
    return x;
  } else {
    return 'foo';
  }
}

This is one of the many refinements that Flow currently can recognize and follow, and we’ll keep adding more! Stay tuned!