I've been struggling getting Flow to type check my code, which heavily uses Preact, and as I was trying to introduce more types, I started running into more and more issues where I wasn't able to type my components and HOCs. I dug a bit deeper into the subject and I believe that the types Preact package provides are simply wrong and aren't used as expected.
I've set up a little example which shows what I mean: https://github.com/smirnowld/flow-preact-issues
It's a simple component rendering another component that requires props. If I render that component without passing any props, Flow doesn't detect any problems. At the same time, similar React example correctly errors out as Flow is able to resolve component types whereas I think Preact types are defaulted to any (essentially skipping type checking altogether).
I've looked at TypeScript definitions for Preact and they seem to be much better than Flow libdefs. Has anyone had much luck getting their Preact components to be correctly typed and checked?
Seems like you're hitting https://github.com/facebook/flow/issues/5469 and https://github.com/facebook/flow/issues/4657
Workarounds:
@jsx h from your scripts, put it on a Babel config instead:presets: [
[
'@babel/preset-react',
{
pragma: 'h',
},
],
'@babel/preset-flow',
],
flow-typed next to .flowconfig, and create a new file called react.js:// @flow
// https://github.com/facebook/flow/issues/4657#issuecomment-323602289
declare var React: $Exports<'react'>;
Thanks @ngyikp , I wasn't aware of these open issues.
I don't see how the first step is relevant for type checking - this babel config will simply strip out Flow types and wrap JSX in h calls. Is this to simply make it run once I remove @jsx h from my source files?
The second step was required once I removed the pragma form my source files (Flow wouldn't run without @jsx h, saying React cannot be resolved), but adding the workaround simply made that error go away without erroring when I rendered a component without required props: https://github.com/smirnowld/flow-preact-issues/tree/workaround-2/preact
Are you actually able to run this somehow and get Flow to report errors? In any case, I'd think that Flow is a popular choice amongst React developers, so docs on how to get it to work with Preact are lacking. I'd be happy to contribute with examples if I actually managed to get this to work.
Worth noting that I tried to get this example to work with preact-compat as well, but since it doesn't export any of the Flow types, it doesn't seem to work "out of the box" for it either.
I've never used Flow, but if you're using preact-compat you should try to use the stock React types.
Yeah, I had tried it. I used the same example for preact-compat as I did for React, swapping out imports:
react example
import * as React from 'react'
import ReactDOM from 'react-dom'
preact-compat example
import * as React from 'preact-compat'
import ReactDOM from 'preact-compat'
The rest is identical. Flow correctly reports errors when using react, but fails to detect anything when using preact-compat. I believe this is because preact-compat doesn't export any types itself, and so Flow marks all exports as any. You'd either have to provide types in preact-compat or create a libdef for it.
@smirnowld hmm - swapping imports is going to confuse Flow though. Ideally you'd import * as React from 'react'; and tell your bundler (webpack, rollup, babel, etc) to alias those to preact-compat. Perhaps that'd fix the issue since Flow would presumably pick up the types from the React package then?
I'll give it a shot, thanks for the new idea. I'll report back once I had a chance to play around with it.
@developit, you're right, my imports were erroneous. If I import from react, alias it to preact-compat (through Webpack in my case), and treat my code as if it were React, then Flow uses React types and correctly typechecks. Doing so in our repository highlighted over 700 issues - cases where Flow was silently ignoring them because it was treating imports from preact as any. Examples are cases where we were not passing required props to components when rendering them; passing props of wrong types; or not dealing with undefined values - pretty dangerous, especially if you trust a tool to guard you from this!
My takeaway from this exercise is that Preact does not support Flow out of the box. The fact that there's a poorly understood and poorly maintained .js.flow file with some of the types led us to believing our code was being typechecked when, in fact, it wasn't.
Flow types only work with React if you use preact-compat and change your imports to "React-style". We were using preact-compat already, but since we were importing directly from Preact and using its types, Flow was treating imports as any, essentially skipping typechecking related code branches.
If there are no Flow experts among Preact's core contributors, I feel it's harmful to provide Flow types in their current shape. TypeScript definitions seem to get a lot of love, and look at how different they are from the ones Preact provides for Flow - it's day and night. I think the best course of action here would be to ditch the types and expand documentation to explain what needs to be done to get Flow to typecheck your Preact components.
Thoughts?
@smirnowld I agree - the existence of flow definitions here is certainly misleading. Unless there's a way to update them to some "baseline" version (eg: no type checking for attributes, etc), I think we'd be open to removing them entirely.
We removed support for flowtypes in master as they were somewhat broken and we don't have experience with flow in the core team. On top of that we didn't receive any PRs to fix those, so we made the decision to remove them.
Most helpful comment
Seems like you're hitting https://github.com/facebook/flow/issues/5469 and https://github.com/facebook/flow/issues/4657
Workarounds:
@jsx hfrom your scripts, put it on a Babel config instead:flow-typednext to.flowconfig, and create a new file calledreact.js: