Skip to content
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

Flow gives an error "Cannot assign [value] to this.[property] because property [property] is missing in [class]" #6356

Open
fterh opened this issue May 25, 2018 · 7 comments

Comments

@fterh
Copy link
Contributor

fterh commented May 25, 2018

This works:

// @flow
import React, {Component} from 'react';


type Props = {};

class Delete extends Component<Props> {
  targetElement: null | winndow.HTMLInputElement;

  constructor(props: Props) {
    super(props);

    this.targetElement = null; // initialize to null
  }

  handleClick = (e: SyntheticEvent<> & {target: window.HTMLInputElement}) => {
    this.targetElement = (e.target: window.HTMLInputElement).value;
  };

  render() {
    return (
      <input onClick={this.handleClick} value="hello" />
    );
  }
}

export default Delete;

but this doesn't:

...
handleClick = (e: SyntheticEvent<> & {target: window.HTMLInputElement}) => {
    this.targetElement = e.target.value;
  };
...

The error message is: Cannot get e.target.value because property value is missing in EventTarget.

  1. I've already typed the "target" property to be window.HTMLInputElement, which has a value property, so why does Flow insist that property value is missing in EventTarget (why EventTarget?)

In the first place, before I added Flow annotations, the code works great, and there were no console errors about missing properties.

I'm really confused as to how this works - I've read this and this, and it seems there are a huge range of workarounds/solutions, but I'm not sure why they work. Also, those are 2-3 years old, and I'm not sure if they're still relevant now. I'm new to Flow, but really interested to master it!

@Ricardo-Marques
Copy link

Ricardo-Marques commented May 25, 2018

I've already typed the "target" property to be window.HTMLInputElement, which has a value property

Not sure what you mean here, but for what it's worth, this is a working version of your example

// @flow
import React, { Component } from 'react'

type Props = {}

class Delete extends Component<Props> {
  targetElement: ?HTMLInputElement

  constructor(props: Props) {
    super(props)

    this.targetElement = null // initialize to null
  }

  handleClick = (e: SyntheticEvent<HTMLInputElement>) => {
    this.targetElement = e.currentTarget
  }

  render() {
    return <input onClick={this.handleClick} value="hello" />
  }
}

export default Delete

@fterh
Copy link
Contributor Author

fterh commented May 26, 2018

Not sure what you mean here, but for what it's worth, this is a working version of your example

I meant I've already specified the "target" property to be of type window.HTMLInputElement:

...
class Delete extends Component<Props> {
> targetElement: null | winndow.HTMLInputElement;

  constructor(props: Props) {
...

Also, is there a difference between HTMLInputElement and Window.HTMLInputElement? I found when experimenting that sometimes interchanging the two breaks the test, but I haven't been able to find a consistent theory/answer for it.

Update: I notice that if I change e.currentTarget to e.target I get an error Cannot assign e.target to this.targetElement because EventTarget [1] is incompatible with HTMLInputElement [2].. Is this supposed to happen? What if I require the "target" property instead of "currentTarget"?

@Ricardo-Marques
Copy link

Window.HTMLInputElement is not a valid type. If flow doesn't error for you when you use it, you might have an issue in your IDE

HTMLInputElement is a built in type

FYI - I like consulting this cheat-sheet whenever I forget what an internal type is called or for quickly finding their source

@Ricardo-Marques
Copy link

Update: I notice that if I change e.currentTarget to e.target I get an error Cannot assign e.target to this.targetElement because EventTarget [1] is incompatible with HTMLInputElement [2].. Is this supposed to happen? What if I require the "target" property instead of "currentTarget"?

There's actually an explanation for that in the source code, which links you here

@fterh
Copy link
Contributor Author

fterh commented May 26, 2018

Window.HTMLInputElement is not a valid type. If flow doesn't error for you when you use it, you might have an issue in your IDE

Flow doesn't error when I use it - I got the idea to try that from an answer to a previous issue. Is it supposed to produce an error? Because it was reported as a solution in that thread.

There's actually an explanation for that in the source code, which links you here

Thank you, I'll have a look!

@Ricardo-Marques
Copy link

It is def supposed to raise an error.
const element: ?window.HTMLInputElement = null
Put that on try flow and you'll see

3: const element: ?window.HTMLInputElement = null
^ Cannot resolve name window.

@fterh
Copy link
Contributor Author

fterh commented May 26, 2018

In that case, I believe this is caused by the create-react-app package. I created a new test project, and installed nothing but flow, and pasted the exact line const element: ?window.HTMLInputElement = null, and flow runs without any errors.

I'm happy to create a demonstration repo!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants