Repository: jsx-eslint/eslint-plugin-react (JavaScript)

Issue:
no-typos doesn't detect invalid PropTypes in static class fields
I've observed this with versions 7.5.1 & 7.6.1. The [docs](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-typos.md) indicate that the following should cause this warning: `Typo in declared prop type: typo` however it doesn't.

```js
class MyComponent extends React.Component {
  static propTypes = {
    a: PropTypes.typo
  }
}
```

However, when you don't use static class fields, it produces the expected warning:

```js
class MyComponent extends React.Component {}
MyComponent.propTypes = {
  a: PropTypes.typo
};
```


Discussion:

Patch:
diff --git a/lib/rules/no-typos.js b/lib/rules/no-typos.js
index f9c798a9fb..4540e5a015 100644
--- a/lib/rules/no-typos.js
+++ b/lib/rules/no-typos.js
@@ -45,7 +45,7 @@ module.exports = {
     let propTypesPackageName = null;
     let reactPackageName = null;
 
-    function checkValidPropTypeQualfier(node) {
+    function checkValidPropTypeQualifier(node) {
       if (node.name !== 'isRequired') {
         context.report({
           node: node,
@@ -101,14 +101,14 @@ module.exports = {
           isPropTypesPackage(node.object.object)
         ) { // PropTypes.myProp.isRequired
           checkValidPropType(node.object.property);
-          checkValidPropTypeQualfier(node.property);
+          checkValidPropTypeQualifier(node.property);
         } else if (
           isPropTypesPackage(node.object) &&
           node.property.name !== 'isRequired'
         ) { // PropTypes.myProp
           checkValidPropType(node.property);
         } else if (node.object.type === 'CallExpression') {
-          checkValidPropTypeQualfier(node.property);
+          checkValidPropTypeQualifier(node.property);
           checkValidCallExpression(node.object);
         }
       } else if (node.type === 'CallExpression') {
@@ -126,8 +126,7 @@ module.exports = {
 
     function reportErrorIfClassPropertyCasingTypo(node, propertyName) {
       if (propertyName === 'propTypes' || propertyName === 'contextTypes' || propertyName === 'childContextTypes') {
-        const propsNode = node && node.parent && node.parent.type === 'AssignmentExpression' && node.parent.right;
-        checkValidPropObject(propsNode);
+        checkValidPropObject(node);
       }
       STATIC_CLASS_PROPERTIES.forEach(CLASS_PROP => {
         if (propertyName && CLASS_PROP.toLowerCase() === propertyName.toLowerCase() && CLASS_PROP !== propertyName) {
@@ -176,7 +175,7 @@ module.exports = {
 
         const tokens = context.getFirstTokens(node, 2);
         const propertyName = tokens[1].value;
-        reportErrorIfClassPropertyCasingTypo(node, propertyName);
+        reportErrorIfClassPropertyCasingTypo(node.value, propertyName);
       },
 
       MemberExpression: function(node) {
@@ -193,9 +192,10 @@ module.exports = {
 
         if (
           relatedComponent &&
-          (utils.isES6Component(relatedComponent.node) || utils.isReturningJSX(relatedComponent.node))
+          (utils.isES6Component(relatedComponent.node) || utils.isReturningJSX(relatedComponent.node)) &&
+          (node.parent && node.parent.type === 'AssignmentExpression' && node.parent.right)
         ) {
-          reportErrorIfClassPropertyCasingTypo(node, propertyName);
+          reportErrorIfClassPropertyCasingTypo(node.parent.right, propertyName);
         }
       },
 


Test patch:
diff --git a/tests/lib/rules/no-typos.js b/tests/lib/rules/no-typos.js
index 8ae187ff5b..ba6b524bac 100644
--- a/tests/lib/rules/no-typos.js
+++ b/tests/lib/rules/no-typos.js
@@ -917,7 +917,6 @@ ruleTester.run('no-typos', rule, {
           a: PropTypes.Number.isRequired
       }
     `,
-    parser: 'babel-eslint',
     parserOptions: parserOptions,
     errors: [{
       message: 'Typo in declared prop type: Number'
@@ -930,11 +929,38 @@ ruleTester.run('no-typos', rule, {
           a: PropTypes.number.isrequired
       }
     `,
+    parserOptions: parserOptions,
+    errors: [{
+      message: 'Typo in prop type chain qualifier: isrequired'
+    }]
+  }, {
+    code: `
+      import PropTypes from "prop-types";
+      class Component extends React.Component {
+        static propTypes = {
+          a: PropTypes.number.isrequired
+        }
+      };
+    `,
     parser: 'babel-eslint',
     parserOptions: parserOptions,
     errors: [{
       message: 'Typo in prop type chain qualifier: isrequired'
     }]
+  }, {
+    code: `
+      import PropTypes from "prop-types";
+      class Component extends React.Component {
+        static propTypes = {
+          a: PropTypes.Number
+        }
+      };
+    `,
+    parser: 'babel-eslint',
+    parserOptions: parserOptions,
+    errors: [{
+      message: 'Typo in declared prop type: Number'
+    }]
   }, {
     code: `
       import PropTypes from "prop-types";