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 issues with IntersectionTypeAnnotation for prop-types and no-unused-prop-types #1415

Merged
merged 9 commits into from
Sep 12, 2017

Conversation

jseminck
Copy link
Contributor

@jseminck jseminck commented Sep 6, 2017

Closes #1413

3 cases needed to be covered:

  • Mutliple intersections:
type PropsA = {}
type PropsB = {}
type PropsC = {}
type PropsD = PropsA & PropsB
type Props = PropsC & PropsD
  • Importing types. This was already handled for other cases, but not for the intersection.
  • type Props = PropsA & { foo: string }

}
}

return ignorePropsValidation;
Copy link
Member

Choose a reason for hiding this comment

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

i can't decide if this style, or early-returning each place this var is assigned, is better

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Honestly I'm in general not really happy about the fact that a function with a name declarePropTypes*** returns a boolean at all. It's a bit confusing. That's why I liked this style a bit more, because it's very explicit to say what those methods return and what the boolean actually means.

Perhaps a try/catch may be even better?

Copy link
Member

Choose a reason for hiding this comment

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

We could rename the function instead :-)

* @returns {Boolean} True if propTypes should be ignored (e.g. when a type can't be resolved, when it is imported)
*/
function declarePropTypesForIntersectionTypeAnnotation(propTypes, declaredPropTypes) {
return propTypes.types.reduce((ignorePropsValidation, annotation) => {
Copy link
Member

Choose a reason for hiding this comment

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

since this is reducing to a boolean, could it use some or every, and that way it will bail early?

}

let types = buildTypeAnnotationDeclarationTypes(value, key);
if (types === true) {
Copy link
Member

Choose a reason for hiding this comment

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

instead of reusing types here, can we use multiple vars and use const?

Copy link
Contributor Author

@jseminck jseminck Sep 7, 2017

Choose a reason for hiding this comment

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

This is from the existing code so didn't touch it yet. But I think we can simply do:

const types = buildTypeAnnotationDeclarationTypes(value, key) || {};
declaredPropTypes.push({
  ...types,
  fullName: key,
  name: key,
  node: value
});

Edit: Ah! We don't support spread operator yet. 😞

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Meh, another problem is that buildTypeAnnotationDeclarationTypes returns either a boolean or an object which isn't great either. I try to refactor it to always return an object, but it needs changes in more places than just here.

But I do think it's a good refactor to do 😄

@jseminck
Copy link
Contributor Author

jseminck commented Sep 7, 2017

Made some additional changes. Did a smoke test on the material-ui code which is currently breaking with rc0. I changed those functions to return early, but haven't changed the name as I couldn't come up with something.

@yannickcr please also have a look as this is required for 7.4.0.

Copy link
Member

@ljharb ljharb left a comment

Choose a reason for hiding this comment

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

Thanks, this looks much better!

@@ -261,7 +262,7 @@ module.exports = {
// If it's a computed property, we can't make any further analysis, but is valid
return key === '__COMPUTED_PROP__';
}
if (propType === true) {
if (typeof propType === 'object' && Object.keys(propType).length === 0) {
Copy link
Member

Choose a reason for hiding this comment

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

What is the typeof guarding against here? This allows null, for example.

Copy link
Contributor Author

@jseminck jseminck Sep 7, 2017

Choose a reason for hiding this comment

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

null would be checked in the if statement before:

if (!propType) {
    // If it's a computed property, we can't make any further analysis, but is valid
    return key === '__COMPUTED_PROP__';
}

Otherwise, if I remove the typeof condition, one test starts failing. Turns out propType is a function() in one of the cases (not sure why) and it satifies the condition Object.keys(propType).length === 0. Perhaps should use https://www.npmjs.com/package/lodash.isplainobject ?

function Hello(props) {
  return <div>{props.name.constructor.firstname}</div>
}
Hello.propTypes = {
  name: PropTypes.shape({
    firstname: PropTypes.object
  })
};:

AssertionError: Should have 1 error but had 0: []

Basically we want to check if its {} instead of true, since those methods always return an object now instead of a boolean.

Copy link
Member

Choose a reason for hiding this comment

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

Gotcha; makes sense.

* @param {Object} declaredPropTypes
* @returns {Boolean} True if propTypes should be ignored (e.g. when a type can't be resolved, when it is imported)
*/
function declarePropTypesForIntersectionTypeAnnotation(propTypes, declaredPropTypes) {
Copy link
Member

Choose a reason for hiding this comment

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

Can these two functions live somewhere they can be shared across the rules that currently duplicate them?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. I'm working on it 😄 The idea will be that the rule will be declared as:

create: propTypes.detect((context, components, utils) => {
...
})

And this will take care of ALL the shared code between prop-types and no-unused-prop-types. Perhaps also for the other rules.

@ljharb ljharb merged commit 7e336aa into jsx-eslint:master Sep 12, 2017
@jseminck jseminck deleted the intersection-imported-type branch November 19, 2017 07:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants