Skip to content

Commit

Permalink
[Fix]:prop-types: handle nullable component in propTypes
Browse files Browse the repository at this point in the history
  • Loading branch information
hank121314 committed Jul 6, 2020
1 parent 6fc4bc0 commit 56a529c
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 42 deletions.
57 changes: 18 additions & 39 deletions lib/util/propTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,23 @@ const variableUtil = require('./variable');
const versionUtil = require('./version');
const propWrapperUtil = require('./propWrapper');
const getKeyValue = require('./ast').getKeyValue;
const findReturnStatement = require('./ast').findReturnStatement;
const isJSX = require('./jsx').isJSX;

/**
* Checks if a node is inside a class body.
*
* @param {ASTNode} node the AST node being checked.
* @returns {Boolean} True if the node has a ClassBody ancestor, false if not.
*/
function isInsideClassBody(node) {
let parent = node.parent;
while (parent) {
if (parent.type === 'ClassBody') {
return true;
}
parent = parent.parent;
}
return false;
}

/**
* Checks if we are declaring a props as a generic type in a flow-annotated class.
Expand Down Expand Up @@ -55,42 +70,6 @@ function iterateProperties(context, properties, fn, handleSpreadFn) {
}
}

/**
* Checks if a node is inside a class body.
*
* @param {ASTNode} node the AST node being checked.
* @returns {Boolean} True if the node has a ClassBody ancestor, false if not.
*/
function isInsideClassBody(node) {
let parent = node.parent;
while (parent) {
if (parent.type === 'ClassBody') {
return true;
}
parent = parent.parent;
}
return false;
}

/**
* Checks if a node is a Function and return JSXElement
*
* @param {ASTNode} node the AST node being checked.
* @returns {Boolean} True if the node is a Function and return JSXElement.
*/
function isJSXFunctionComponent(node) {
if (node.type === 'ArrowFunctionExpression' || node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression') {
const res = findReturnStatement(node);
// If function return JSXElement with return keyword.
if (res) {
return isJSX(res.argument);
}
// If function return JSXElement without return keyword;
return isJSX(node.body);
}
return false;
}

module.exports = function propTypesInstructions(context, components, utils) {
// Used to track the type annotations in scope.
// Necessary because babel's scopes do not track type annotations.
Expand Down Expand Up @@ -649,7 +628,7 @@ module.exports = function propTypesInstructions(context, components, utils) {
}

// Should ignore function that not return JSXElement
if (!isJSXFunctionComponent(node)) {
if (!utils.isReturningJSXOrNull(node)) {
return;
}

Expand Down
2 changes: 1 addition & 1 deletion tests/lib/rules/no-unused-prop-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -3404,7 +3404,7 @@ ruleTester.run('no-unused-prop-types', rule, {
': Props): JSX.Element {',
'const handleVerifySubmit = ({',
' otp,',
' }) => {',
' }: {otp:string}) => {',
' dispatch(',
' verifyOTPPhone({',
' otp,',
Expand Down
63 changes: 61 additions & 2 deletions tests/lib/rules/prop-types.js
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -2493,8 +2493,7 @@ ruleTester.run('prop-types', rule, {
{
code: `
interface Props {
'aria-label': string // 'undefined' PropType is defined but prop is never used eslint(react/no-unused-prop-types)
// 'undefined' PropType is defined but prop is never used eslint(react-redux/no-unused-prop-types)
'aria-label': string;
}
export default function Component({
Expand All @@ -2504,6 +2503,51 @@ ruleTester.run('prop-types', rule, {
}
`,
parser: parsers.TYPESCRIPT_ESLINT
},
{
code: `
interface Props {
value?: string;
}
// without the | null, all ok, with it, it is broken
function Test ({ value }: Props): React.ReactElement<Props> | null {
if (!value) {
return null;
}
return <div>{value}</div>;
}`,
parser: parsers.TYPESCRIPT_ESLINT
},
{
code: `
interface Props {
value?: string;
}
// without the | null, all ok, with it, it is broken
function Test ({ value }: Props): React.ReactElement<Props> | null {
if (!value) {
return <div>{value}</div>;;
}
return null;
}`,
parser: parsers.TYPESCRIPT_ESLINT
},
{
code: `
interface Props {
value?: string;
}
const Hello = (props: Props) => {
if(props.value) {
return <div></div>;
}
return null;
}`,
parser: parsers.TYPESCRIPT_ESLINT
}
],

Expand Down Expand Up @@ -4949,6 +4993,21 @@ ruleTester.run('prop-types', rule, {
{
message: '\'ordering\' is missing in props validation'
}]
},
{
code: `
interface Props {
}
const Hello = (props: Props) => {
if(props.value) {
return <div></div>;
}
return null;
}`,
parser: parsers.TYPESCRIPT_ESLINT,
errors: [{
message: '\'value\' is missing in props validation'
}]
}
]
});

0 comments on commit 56a529c

Please sign in to comment.