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

Fix type annotation properties assigning to undefined. (#8417) #8584

Closed

Conversation

allex
Copy link

@allex allex commented Aug 30, 2018

Q                       A
Fixed Issues? Fixes #8417
Patch: Bug Fix?
Major: Breaking Change?
Minor: New Feature?
Tests Added + Pass? Yes
Documentation PR Link
Any Dependency Changes? Add a helper declareNilProps (obj, props); to @babel/babel-helpers
License MIT

@babel-bot
Copy link
Collaborator

babel-bot commented Aug 30, 2018

Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/8978/

@@ -1053,3 +1053,12 @@ helpers.classPrivateFieldSet = helper("7.0.0-beta.0")`
return value;
}
`;

helpers.declareNilProps = helper("7.0.0-beta.0")`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be 7.0.1, since it represents the first version where the helper is available.

@nicolo-ribaudo
Copy link
Member

I don't undertand why the _declareNilProps helper is needed. Why should x: number create a property on the class if it doesn't have an initializer? Isn't it just a type annotation?

@allex allex force-pushed the babel-plugin-proposal-class-properties branch 2 times, most recently from c16a4c3 to 06f7846 Compare August 30, 2018 09:48
@loganfsmyth
Copy link
Member

I don't see us landing this without a serious discussion with the folks developing the class fields specification and Flow folks. What you're proposing means that if you have

class Foo {
  x;
  y;
}

console.log("x" in new Foo());

in an existing codebase, and you want to convert the codebase to Flow by doing

class Foo {
  x: number;
  y: number;
}

console.log("x" in new Foo());

the behavior of the code would change based on the addition of a type annotation, which seems like it would be incredibly surprising.

@nicolo-ribaudo
Copy link
Member

@loganfsmyth We already remove x: foo; if the flow plugin runs before the class-properties one. I think that we should fix this inconsistency.

FWIW, I opened facebook/flow#6811 yesterday but it isn't getting much attention from the flow team 😕

@loganfsmyth
Copy link
Member

@nicolo-ribaudo Yeah, the inconsistency is unfortunate, but I think changing it at this stage would be even more confusing. Maybe once we've had all the discussions with Flow and spec folks we can revisit.

@c0d3m3nt0r
Copy link

c0d3m3nt0r commented Aug 30, 2018

@loganfsmyth, that scenario you mention makes sense, I mean, if you declared two class variables, and then you do not initialize them, they will remain undefined, which is expected, I think, at least I wouldn't expect another behavior in that case.

The thing gets inconsistent, at least from my point of view, when after declaring a variable, like in your example, but having in mind that variable is an arrow function, when it later gets initialized in the code, at the time the constructor gets executed, that variable remains undefined, like in react-native createAnimatedComponent() source code, and as I explained here, there, is in where things turn out to be inconsistent.

In my opinion, I believe this is related to the part in where class properties are being processed, I would have expected @babel/proposal-class-properties took care of these kind of use cases and output the correct class properties initialization, in where (in the case I pointed) the variable should be other than undefined.

The easiest path would be, in my case, to make react-native team to consider removing the Flow type annotation for the arrow function at the top of their class, and just initialize the arrow function as they do later in their code (and at the same time make it more accurate, in terms of parameter types and return type), and that should fix the issue, but, the problem is all other libraries that are doing the same thing, having in mind this issue is not happening with Babel 6.x.

So, having that in mind, how can we solve this situation?, should we ask everyone to adjust their code in order to workaround this issue? (besides we agree or not that one is a good practice or makes sense or not) or to find a backward compatible solution to make current libraries having the same issue to have their pipeline back to work?

Sooner or later someone will fix this, but in the meantime, the code starts to get full or workarounds to get rid of these kind of issues when moving to Babel 7. I have upgraded to the latest stable version of babel (7.0.0), and I have to recognize several issues were fixed since the beta.47, which is a great job to address those issues to finally arrive to something more stable, but this one it is still there, and it would be great to have it fixed at some point :)

Thank you for your support and effort to keep making Babel such a great tool.

ver: number
ver = x;

fn: Function
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@allex, would you mind to try something like the following?

class A {
   fn: Function;
   constructor() {
      this.fn = this.fn.bind(this);
   }
   fn = () => {
      return 'hey!';
   }
}

I'm interested on determine whether the constructor will throw TypeError: Cannot read property 'bind' of undefined (due to fn gets initialized to undefined) or the code runs successfully having resolved fn to the actual arrow function value defined later in the example.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it's should be ok, seem like:

  class A {
    fn: Function;
    constructor() {
      this.fn = this.fn.bind(this);
    }
    fn = () => {
      return 'hey!';
    }
  }

  const a = new A();
  expect(a.fn()).toBe('hey!')

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool, thanks 👍

@allex allex force-pushed the babel-plugin-proposal-class-properties branch from 37e660b to a341c06 Compare August 31, 2018 05:31
Copy link
Member

@nicolo-ribaudo nicolo-ribaudo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am ok with mergint this, since it what we alread do when the flow plugin runs before the class-properties one.
Also, its what flow currently does:

➜ npx flow-remove-types
npx: installed 3 in 0.757s
> class A {
... constructor() { this.x = 2 }
... }
undefined
> class B extends A {
... x: number;
... }
undefined
> new B().x
2
> 

If the flow teams decides that this behavior is wrong, we can change it in the future.

@torkelo
Copy link

torkelo commented Nov 23, 2018

Any update to get this merged? This is causing issue wtih typescript + babel

@nicolo-ribaudo
Copy link
Member

I'm closing this PR because you can already use declare for class fields with TypeScript to avoid initializing them to undefined, and starting from Babel 7.9.0 it will also be supported by Flow (#11178).

Thanks @allex anyway!

@github-actions github-actions bot added the outdated A closed issue/PR that is archived due to age. Recommended to make a new issue label Jun 17, 2020
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jun 17, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
outdated A closed issue/PR that is archived due to age. Recommended to make a new issue
Projects
None yet
Development

Successfully merging this pull request may close these issues.

v7 plugin-proposal-class-properties transform flow type annotation to undefined
6 participants