Here is an ES6 class component:
import React from 'react'
type Props = {
foo: number,
};
class ExampleClass extends React.Component<{}, Props, {}> {
render() {
return <div>{this.props.foo}</div>
}
}
const testClass = <ExampleClass foo="string" /> // error
This works as expected, but how do you annotate a stateless functional component? This is the best I could do, but it doesn't produce an error and it should.
import React from 'react'
type Props = {
foo: number,
};
function ExampleFunction({foo}: Props): ReactElement {
return <div>{foo}</div>
}
const testFunction = <ExampleFunction foo="string" /> // no error
edit: Renamed the examples so the names don't conflict.
I dug into this as far as I could, and here is what I could find:
Type of a React element. React elements are commonly created using JSX
literals, which desugar to React.createElement calls (see below).
source
So this leads me to createElement
declare function createElement<DefaultProps, Props, State, A: $Diff<Props, DefaultProps>>(
name: ReactClass<DefaultProps, Props, State>,
attributes: A,
children?: any
): ReactElement<DefaultProps, Props, State>;
So Flow is aware that <ExampleClass foo="string" />
will desugar to React.createElement(ExampleClass, { foo: "string" })
and it type checks that. When using a functional component the type isn't ReactClass<DefaultProps, Props, State>
. But why doesn't Flow complain that I just passed it a Function
and not a ReactClass<DefaultProps, Props, State>
?
// This works as expected
const testClass2 = React.createElement(ExampleClass, { foo: 1 })
// this one complains that the first parameter is the wrong type:
// ========================
// call of method `createElement`
// string. This type is incompatible with
// class type: existential. See: /tmp/flow/flowlib_e5f5399/react.js:132
const testString = React.createElement("Hello", { foo: 1 })
// No error here even though I didn't pass a ReactClass<DefaultProps, Props, State>
const testFunction2 = React.createElement(ExampleFunction, { foo: 1 })
Not a solution, but just to explain the way things are right now: the current React definitions were designed with React 0.13 in mind. I don't have all the inside scoop here, but personally I am hoping that we roll the 0.14 type definitions into React itself, to avoid the versioning nightmare that comes from vendoring React's interfaces directly into Flow.
Any update on this? Is it possible to annotate function based components now?
I ended up doing this for now:
/* @flow */
import React from 'react';
...
export default (props: {
notes: Array<Object>,
onValueClick: Function,
onEdit: Function,
onDelete: Function
}): ReactElement => {
const {notes, onValueClick, onEdit, onDelete} = props;
return (
...
);
}
Does the approach look good to you? Any gotchas apart from destructuring?
I can't verify because I was forced to simply abandon Flow, but the core problem was that with 0.13 components typing <Foo />
in one file would be able to tell you you're missing parameter bar
, or that it's the wrong type or whatever. From the best I remember of what I found if your component is a function Flow couldn't make the connection between <Foo />
and what function Foo
required. I was able to verify internal consistency of the component, but not that it's actually being called correctly from another file.
If I understand your attempt correctly I think it will have the same problem. Flow won't catch missing or wrong parameters in <YourComponent />
style calls.
@AsaAyers Alright. Thanks for getting back to me.
There's actually an extra problem I forgot to mention. It should be possible to set some sane default values for the parameters. For example that onDelete
might be undefined
(probably need to change type annotation). In this case it would be nice to default to () => {}
(noop).
Maybe it makes sense to use propTypes
for function based components for the time being. I know you'll be missing out some of the benefits of Flow given then we end up checking the types on runtime, but it's better than nothing. And it solves the problem of default values well.
No updates in here for a month, so is it now possible to annotate stateless functional components?
This here does not produce any flow error:
https://gist.github.com/Thorbenandresen/510af38264b0e34b2f5e
Nope. Still not possible. No React or Flow releases have happened in the past month either, but it will likely be a release or two before a solution is reached.
Disclaimer: I’m not on either team in any capacity.
It seems this solve the problem:
Only today discovered that Flow actually supports type-checking of props passed to React components, but you have to add a line like ._/node_modules/react(-dom)?/._ to your .flowconfig [ignore] to make it work, because otherwise the React library (without type definitions) overrides Flow's built-in React definitions. I'm really surprised there's such a useful feature hidden by an issue like this.
[https://github.com/facebook/flow/issues/676]
@bebraw your approach now works, flow throws an error.
is there any way I can set a default value here? this obv doesn't work..
const Header = (props: {
isAdmin: boolean = false,
dispatch: Function
}) => (
<Toolbar style={style.bar}>
...
By the way, I came here from your book, It's excellent!
@Nor145 your syntax is a little wrong here. Default values shouldn't be part of the type definition! :)
const Header = (props: {
isAdmin: boolean,
dispatch: Function
} = {isAdmin: false}) => (
<Toolbar style={style.bar}>
...
Would provide a default for the props
parameter but that's no good if you pass {dispatch}
since it gets overridden. If you just want a default for one or two properties in an object parameter you can use destructuring and default values like the following:
const Header = ({isAdmin = false, ...props}: {
isAdmin: boolean ,
dispatch: Function
}) => (
<Toolbar style={style.bar}>
...
That's assuming flow handles the left side being an object anyway!
@Chrisui Thanks for answering. Your second approach is right, but seems there is not support for this feature yet.
[https://github.com/facebook/flow/issues/183]
On a side note, it looks like the new comment style syntax doesn't work with stateless components.
Is there an available workaround to enable flow checks on Stateless Function components from JSX until proper support is added ?
Given that it's considered best practice to use SFCs as much as possible this issue seems pretty critical to be fixed.
Just wanted to say that flow has constantly faced issues with new syntax, which has never enabled me or most of the teams I know to have proper type coverage. This issue in particular and the lack of core team communication and "openness" made me take the decision of dropping flow from all projects I have some control over today.
I wonder if @marudor has a suggested answer to your question @gcazaciuc ? I could really use this too.
@glortho sorry, can't help with that.
Some quick tests I tried didn't work.
This can be closed
Not sure about leaving this open or creating a new issue but I think this is not quite finished, for example, the documentation on react still says "Support for stateless functional components is coming soon". After reading the documentation on the other ways of building react components, I thought flow could read the propType
definition and I didn't have to convert all existing code to use flow annotations? This module fails with flow 0.26.0:
// @flow
import React from 'react';
const Y = (props) => <div>{props.bar}</div>;
const X = (props) => <Y bar={props.foo} />;
X.propTypes = {
foo: React.PropTypes.string.isRequired
};
export default X;
that it would type check, but flow fails with:
src/app/foo.js:6
6: const X = (props) => <Y foo={props.foo} />;
^^^^^ parameter `props`. Missing annotation
I'm not using propTypes I'm using flow type annotations with stateless
components and it works great.
So maybe it's a new issue?
On 30 May 2016 at 16:19, Christoph Neuroth [email protected] wrote:
Not sure about leaving this open or creating a new issue but I think this
is not quite finished, for example, the documentation on react
http://flowtype.org/docs/react.html#_ still says "Support for stateless
functional components is coming soon". After reading the documentation on
the other ways of building react components, I thought flow could read the
propType definition and I didn't have to convert all existing code to use
flow annotations? This module fails with flow 0.26.0:// @flow
import React from 'react';
const Y = (props) =>{props.bar};
const X = (props) =>;
X.propTypes = {
foo: React.PropTypes.string.isRequired
};
export default X;that it would type check, but flow fails with:
src/app/foo.js:6
6: const X = (props) =>;
^^^^^ parameterprops
. Missing annotation—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/facebook/flow/issues/1081#issuecomment-222419320, or mute
the thread
https://github.com/notifications/unsubscribe/ACA_f-4auRjSM2PjPdN3JHLv0EU3uQwOks5qGoGKgaJpZM4GgUev
.
I'm not using propTypes I'm using flow type annotations with stateless
components and it works great.
Hm, I'm a bit confused about the feature then: When not using propTypes
, a stateless component is just a plain JS function that happens to return a React.Element
and adding flow type annotations to this would have worked before 0.26 then, wouldn't it?
It's a little different as you don't explicitly call the function, it gets
compiled from jsx. At least in my case that is.
But it wasn't working before and is now as of 0.26
On 30 May 2016 at 16:26, Christoph Neuroth [email protected] wrote:
I'm not using propTypes I'm using flow type annotations with stateless
components and it works great.Hm, I'm a bit confused about the feature then: When not using propTypes,
a stateless component is just a plain JS function and adding flow type
annotations to this would have worked before 0.26 then, wouldn't it?—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/facebook/flow/issues/1081#issuecomment-222420160, or mute
the thread
https://github.com/notifications/unsubscribe/ACA_fxrC5P0RixkvIF6ME1_eLA0fOHMlks5qGoMTgaJpZM4GgUev
.
The docs are outdated. I am going to update them soon to reflect our support for stateless functional components.
Regarding PropTypes, Flow understands PropTypes for components created using React.createClass
but currently not for components declared using classes or stateless functional components. For classes and functions it's possible to use Flow type annotations, which are recommended.
@samwgoldman thanks for the explanation and your work 💖
@samwgoldman awesome, thanks. there is one more thing I can't figure out right now: how can we handle the implicit children
prop? This fails:
/*:: type XProps = { children: React.Element[] }; */
const X = ({children}/*:XProps*/) => (<div>{children}</div>);
const Y = () => (<X><span>children</span></X>);
39: const Y = () => (<X><span>children</span></X>);
^^^ React element `X`
38: const X = ({children}/*:XProps*/) => (<div>{children}</div>);
^^^^^^ property `children`. Property not found in
39: const Y = () => (<X><span>children</span></X>);
^^^ props of React element `X`
Having the same issue as this ☝️ - would love a solution!
Should this issue be reopened for the children
case described above?
Never mind, its been raised in #1964 and #1934
For future spelunkers, here's the docs for typing functional components.
Updated link, for reference: https://flow.org/en/docs/react/components/#toc-stateless-functional-components
Most helpful comment
Is there an available workaround to enable flow checks on Stateless Function components from JSX until proper support is added ?
Given that it's considered best practice to use SFCs as much as possible this issue seems pretty critical to be fixed.