-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[React] Flow loses the inferred type of imported functions when using typeof inside Component<Props> #6797
Comments
Seems like flow is marking |
Maybe it was not clear, so here is another example with some comments: // index.js
// @flow
// Let's import a function I've written in my project, with the '// @flow' annotation:
import { action } from '../state/actions'
// action: (param1: string) => {| type: string, param1: string |}
// This is the type inferred by Flow. I can see it in my editor.
// Now let's call it with some unexpected params:
action(1, 2, 3)
// Error 1: Cannot call `action` with `1` bound to `param1` because number [1] is incompatible with string [2]
// Error 2: Cannot call `action` because no more than 1 argument is expected by function [1]
// In this first case, Flow is catching all the errors as expected.
// Now let's pass 'action' to a component through its props:
const mapActionsToProps = {
action
}
type Actions = typeof mapActionsToProps
type Props = {|
...Actions,
otherProp: string,
|}
class MyComponent extends Component<Props> {
componentDidMount() {
this.props.action(1, 2, 3)
// In this case, no errors! Flow is not catching anything.
// Yet it's the exact same function, passed through the Props
}
}
connect(null, mapActionsToProps)(MyComponent) So, either I'm not typing the Props correctly, either there is a bug somewhere. |
I'd try doing: type Props = {|
...$Exact<Actions>,
otherProp: string,
|} |
@AlicanC Just tried and it doesn't fix it. Actually const mapActionsToProps = {
action
}
type Actions = typeof mapActionsToProps already defines |
So I just discovered that it's actually because I was trying to reproduce the bug on flow.org/try but it works as expected when it is in the same file: https://flow.org/try/#0JYWwDg9gTgLgBAJQKYEMDGMA0cDecDCE4EAdkifAL5wBmURcA5FKhowFDtqkDO86MYKTgBeOAAowKKChABGAFxw+UYCQDmASlEA+CXhgBPMEiWMAgvgAqASQDyAOUbYpM+XEqbOAoSXFzsACZsAGYvdiMTOAAFejAeUVwAHzgAOnTzDF8EpMpONAAbFB4EgDEICDgkAA8YcgATBMJiMgoAHliIeL0cdjg4bhbyGAARYHqAWQgAVwpxbV7+-pgAC2AeVLA4jZ9SfyDQr368vK5efizeRMW4XZIlh8en55el9lPIpDhMwSuxT4gNFulxIPCAA I also confirm that the type of the imported import { action } from '../state/actions'
// action: (param1: string) => {| type: string, param1: string |}
const mapActionsToProps = {
action
}
type Actions = typeof mapActionsToProps
type Props = {| ...Actions |}
class MyComponent extends Component<Props> {
componentDidMount() {
action(1, 2, 3) // Error 1: Cannot call `action` with `1` bound to `param1` because number [1] is incompatible with string [2]
// Error 2: Cannot call `action` because no more than 1 argument is expected by function [1]
this.props.action(1, 2, 3) // No errors!
}
} And if in the same file, it works as expected: const action = (param1: string) => ({ type: 'ACTION', param1 })
// action: (param1: string) => {| type: string, param1: string |}
const mapActionsToProps = {
action
}
type Actions = typeof mapActionsToProps
type Props = {| ...Actions |}
class MyComponent extends Component<Props> {
componentDidMount() {
action(1, 2, 3) // Error 1: Cannot call `action` with `1` bound to `param1` because number [1] is incompatible with string [2]
// Error 2: Cannot call `action` because no more than 1 argument is expected by function [1]
this.props.action(1, 2, 3) // Error 1: Cannot call `action` with `1` bound to `param1` because number [1] is incompatible with string [2]
// Error 2: Cannot call `action` because no more than 1 argument is expected by function [1]
}
} So there is a bug when combining |
@ggregoire have you found a workaround for this or what did you end up doing? |
@kangax No I didn't find any workaround. I write the type of every action that I pass to my components… type Props = {|
action: (param1: string) => {| type: string, param1: string |},
action2: () => void,
// and so on…
|}
class MyComponent extends Component<Props> { ... } |
@ggregoire I'm seeing a similar issue where props lose their types: The shape seems to be determined properly: But the 2nd level props are I also checked with ➜ git:(master) ✗ flow type-at-pos app/scripts/xxx.jsx 10 27
{byUuid: {[string]: Array<Ticket>}, error: mixed, loaded: boolean, loading: boolean}
➜ git:(master) ✗ flow type-at-pos app/scripts/xxx.jsx 10 37
any It's pretty bizarre how Flow recognizes this shape correctly but then reports property's value in the same expression as @mroch any hints on what this could be? |
@kangax I don't know if this is related to my issue. In your screenshot, If you remove |
@ggregoire I felt it might be the same issue because:
In my case, however, importing GlobalState or defining it locally doesn't make a difference. |
These import related issues should be resolved a long time ago since types first |
Edit: last update on this: it appears only when 'action' is imported.
--
I don't know if I'm doing something wrong or if it's a bug, but it looks pretty straightforward:
Flow correctly infers the type of the function outside of the component. But, once it is passed to the component (
this.props.action
), it becomesany
.I also tried, without success:
The text was updated successfully, but these errors were encountered: