8

I am using react v16.3.0 and flow-bin v0.69.0

Using react Fragments with either <React.Fragment> or the shorthand <></> syntax like so

import React from 'react'

const ComponentA = () => (
  <React.Fragment>
    <div>Component</div>
    <div>A</div>
  </React.Fragment>
)

const ComponentB = () => (
  <>
    <div>Component</div>
    <div>B</div>
  </>
)

Flow complains with the following error (it's an indentical error for both, just showing output for ComponentA here)

Cannot get React.Fragment because property Fragment is missing in object type [1].

  24│ const ComponentA = () => (
  25│   <React.Fragment>
  26│     <div>Component</div>
  27│     <div>A</div>
  28│   </React.Fragment>

 /private/tmp/flow/flowlib_2349df3a/react.js
 251│   declare export default {|
 252│     +DOM: typeof DOM,
 253│     +PropTypes: typeof PropTypes,
 254│     +version: typeof version,
 255│     +initializeTouchEvents: typeof initializeTouchEvents,
 256│     +checkPropTypes: typeof checkPropTypes,
 257│     +createClass: typeof createClass,
 258│     +createElement: typeof createElement,
 259│     +cloneElement: typeof cloneElement,
 260│     +createFactory: typeof createFactory,
 261│     +isValidElement: typeof isValidElement,
 262│     +Component: typeof Component,
 263│     +PureComponent: typeof PureComponent,
 264│     +Children: typeof Children,
 265│   |};

With an explicit import of Fragment, however, flow does not complain.

import { Fragment, default as React } from 'react'

const ComponentC = () => (
  <Fragment>
    <div>Component</div>
    <div>C</div>
  </Fragment>
)

What is going on here? I would like to use the <></> Fragment shorthand syntax, and this issue is stopping me from doing that for now.

When I dig into the react.js lib def referenced in the error it does appear that the error is factually correct - the export of Fragment is defined and Fragment is not defined as a property on the default export.

But the flow docs state that flow has support for react Fragments from v0.59 onwards.

So is this actually a gap in support that still exists? Or am I doing something wrong? Perhaps I somehow have an outdated lib def or have things configured wrong? I can't find anything googling for the error message, which leads me to suspect it's an issue with my setup. Also I can't quite believe that this wouldn't work out the box.

davnicwil
  • 28,487
  • 16
  • 107
  • 123

3 Answers3

7

You have to use import * as React from 'react' to fix this :)

Aldredcz
  • 87
  • 3
  • 2
    Thanks for that - it does make the flow error go away. However it also takes `React` out of scope meaning JSX doesn't compile. I know I could throw some workaround into the build for that, but it's quite non-standard and doesn't feel worth it just to remove this annoyance (I'd rather just have the extra verbosity of importing and using ``). Thanks anyway. – davnicwil Mar 17 '18 at 12:13
  • 1
    Actually, this is the syntax I use in my whole app. Arguably, `import * as React from 'react'` is the more correct syntax, and the other is just a Babel shim and not real ES6. https://discuss.reactjs.org/t/es6-import-as-react-vs-import-react/360/10 – Patrick Jun 26 '18 at 22:19
7

The fix to include React.Fragment in the definition is included in this commit: https://github.com/facebook/flow/commit/b76ad725177284681d483247e89739c292ed982b

It should be available in flow 0.71

Delapouite
  • 9,469
  • 5
  • 36
  • 41
  • Thanks for the update, good to know. When this lands I'll accept your answer :-) – davnicwil Apr 24 '18 at 17:22
  • flow 0.71 is out. I tried your snippet and it's not complaining anymore. The change about Fragment is mentioned in the changelog : https://github.com/facebook/flow/releases/tag/v0.71.0 – Delapouite May 04 '18 at 07:58
  • Can also confirm it's working now with 0.71.0. Thanks! – davnicwil May 04 '18 at 10:53
2

As simple as:

import * as React from 'react'

const Component = (): React.Element<typeof React.Fragment> => (
  <>
    <span> / </span>
    <span> \ </span>
  </>
)

export default Component
Neurotransmitter
  • 6,289
  • 2
  • 51
  • 38