Skip to content

Commit c02f952

Browse files
committed
Add support for props destructuring directly on the this keyword
1 parent 0b756b5 commit c02f952

File tree

2 files changed

+75
-19
lines changed

2 files changed

+75
-19
lines changed

lib/rules/prop-types.js

Lines changed: 49 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -360,22 +360,46 @@ module.exports = function(context) {
360360
function markPropTypesAsUsed(node, parentNames) {
361361
parentNames = parentNames || [];
362362
var type;
363-
var name = getPropertyName(node.parent);
363+
var name;
364364
var allNames;
365-
if (name) {
366-
allNames = parentNames.concat(name);
367-
if (node.parent.type === 'MemberExpression') {
368-
markPropTypesAsUsed(node.parent, allNames);
369-
}
370-
// Do not mark computed props as used.
371-
type = name !== '__COMPUTED_PROP__' ? 'direct' : null;
372-
} else if (
373-
node.parent.parent.declarations &&
374-
node.parent.parent.declarations[0].id.properties &&
375-
getKeyValue(node.parent.parent.declarations[0].id.properties[0])
376-
) {
377-
type = 'destructuring';
365+
var properties;
366+
switch (node.type) {
367+
case 'MemberExpression':
368+
name = getPropertyName(node.parent);
369+
if (name) {
370+
allNames = parentNames.concat(name);
371+
if (node.parent.type === 'MemberExpression') {
372+
markPropTypesAsUsed(node.parent, allNames);
373+
}
374+
// Do not mark computed props as used.
375+
type = name !== '__COMPUTED_PROP__' ? 'direct' : null;
376+
} else if (
377+
node.parent.parent.declarations &&
378+
node.parent.parent.declarations[0].id.properties &&
379+
getKeyValue(node.parent.parent.declarations[0].id.properties[0])
380+
) {
381+
type = 'destructuring';
382+
properties = node.parent.parent.declarations[0].id.properties;
383+
}
384+
break;
385+
case 'VariableDeclarator':
386+
type = 'destructuring';
387+
388+
for (var i = 0, j = node.id.properties.length; i < j; i++) {
389+
if (
390+
(node.id.properties[i].key.name !== 'props' && node.id.properties[i].key.value !== 'props') ||
391+
node.id.properties[i].value.type !== 'ObjectPattern'
392+
) {
393+
continue;
394+
}
395+
properties = node.id.properties[i].value.properties;
396+
break;
397+
}
398+
break;
399+
default:
400+
throw new Error(node.type + ' ASTNodes are not handled by markPropTypesAsUsed');
378401
}
402+
379403
var component = componentList.getByNode(context, node);
380404
var usedPropTypes = component && component.usedPropTypes || [];
381405

@@ -392,17 +416,16 @@ module.exports = function(context) {
392416
});
393417
break;
394418
case 'destructuring':
395-
var properties = node.parent.parent.declarations[0].id.properties;
396-
for (var i = 0, j = properties.length; i < j; i++) {
397-
if (hasSpreadOperator(properties[i])) {
419+
for (var k = 0, l = properties.length; k < l; k++) {
420+
if (hasSpreadOperator(properties[k])) {
398421
continue;
399422
}
400-
var propName = getKeyValue(properties[i]);
423+
var propName = getKeyValue(properties[k]);
401424
if (propName) {
402425
usedPropTypes.push({
403426
name: propName,
404427
allNames: [propName],
405-
node: properties[i]
428+
node: properties[k]
406429
});
407430
}
408431
}
@@ -509,6 +532,13 @@ module.exports = function(context) {
509532
markPropTypesAsDeclared(node, node.value);
510533
},
511534

535+
VariableDeclarator: function(node) {
536+
if (node.init.type !== 'ThisExpression' || node.id.type !== 'ObjectPattern') {
537+
return;
538+
}
539+
markPropTypesAsUsed(node);
540+
},
541+
512542
MemberExpression: function(node) {
513543
var type;
514544
if (isPropTypesUsage(node)) {

tests/lib/rules/prop-types.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -890,6 +890,32 @@ eslintTester.addRuleTest('lib/rules/prop-types', {
890890
errors: [
891891
{message: '\'arr[].some.value\' is missing in props validation for Hello'}
892892
]
893+
}, {
894+
code: [
895+
'class Hello extends React.Component {',
896+
' render() {',
897+
' let {props: {firstname}} = this;',
898+
' return <div>Hello {firstname}</div>;',
899+
' }',
900+
'}'
901+
].join('\n'),
902+
parser: 'babel-eslint',
903+
errors: [
904+
{message: '\'firstname\' is missing in props validation for Hello'}
905+
]
906+
}, {
907+
code: [
908+
'class Hello extends React.Component {',
909+
' render() {',
910+
' var {\'props\': {firstname}} = this;',
911+
' return <div>Hello {firstname}</div>;',
912+
' }',
913+
'}'
914+
].join('\n'),
915+
parser: 'babel-eslint',
916+
errors: [
917+
{message: '\'firstname\' is missing in props validation for Hello'}
918+
]
893919
}
894920
]
895921
});

0 commit comments

Comments
 (0)