Skip to content

[Refactor] extract type parameters to a variable #3634

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

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,14 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
* [`jsx-key`]: detect conditional returns ([#3630][] @yialo)
* [`jsx-newline`]: prevent a crash when `allowMultilines ([#3633][] @ljharb)

### Changed
* [Refactor] `propTypes`: extract type params to var ([#3634][] @HenryBrown0)
* [Refactor] [`boolean-prop-naming`]: invert if statement ([#3634][] @HenryBrown0)
* [Refactor] [`function-component-definition`]: exit early if no type params ([#3634][] @HenryBrown0)
* [Refactor] [`jsx-props-no-multi-spaces`]: extract type parameters to var ([#3634][] @HenryBrown0)

[#3638]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3638
[#3634]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3634
[#3633]: https://github.com/jsx-eslint/eslint-plugin-react/issues/3633
[#3630]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3630
[#3623]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3623
Expand Down
27 changes: 16 additions & 11 deletions lib/rules/boolean-prop-naming.js
Original file line number Diff line number Diff line change
Expand Up @@ -240,19 +240,24 @@ module.exports = {
}

if (
component.node.parent
&& component.node.parent.type === 'VariableDeclarator'
&& component.node.parent.id
&& component.node.parent.id.type === 'Identifier'
&& component.node.parent.id.typeAnnotation
&& component.node.parent.id.typeAnnotation.typeAnnotation
&& component.node.parent.id.typeAnnotation.typeAnnotation.typeParameters
&& (
component.node.parent.id.typeAnnotation.typeAnnotation.typeParameters.type === 'TSTypeParameterInstantiation'
|| component.node.parent.id.typeAnnotation.typeAnnotation.typeParameters.type === 'TypeParameterInstantiation'
!component.node.parent
|| component.node.parent.type !== 'VariableDeclarator'
|| !component.node.parent.id
|| component.node.parent.id.type !== 'Identifier'
|| !component.node.parent.id.typeAnnotation
|| !component.node.parent.id.typeAnnotation.typeAnnotation
) {
return;
}

const annotationTypeParams = component.node.parent.id.typeAnnotation.typeAnnotation.typeParameters;
if (
annotationTypeParams && (
annotationTypeParams.type === 'TSTypeParameterInstantiation'
|| annotationTypeParams.type === 'TypeParameterInstantiation'
)
) {
return component.node.parent.id.typeAnnotation.typeAnnotation.typeParameters.params.find(
return annotationTypeParams.params.find(
(param) => param.type === 'TSTypeReference' || param.type === 'GenericTypeAnnotation'
);
}
Expand Down
12 changes: 5 additions & 7 deletions lib/rules/function-component-definition.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,12 @@ const UNNAMED_FUNCTION_TEMPLATES = {
};

function hasOneUnconstrainedTypeParam(node) {
if (node.typeParameters) {
return (
node.typeParameters.params.length === 1
&& !node.typeParameters.params[0].constraint
);
}
const nodeTypeParams = node.typeParameters;

return false;
return nodeTypeParams
&& nodeTypeParams.params
&& nodeTypeParams.params.length === 1
&& !nodeTypeParams.params[0].constraint;
}

function hasName(node) {
Expand Down
8 changes: 6 additions & 2 deletions lib/rules/jsx-props-no-multi-spaces.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,12 @@ module.exports = {
}

function containsGenericType(node) {
const containsTypeParams = typeof node.typeParameters !== 'undefined';
return containsTypeParams && node.typeParameters.type === 'TSTypeParameterInstantiation';
const nodeTypeParams = node.typeParameters;
if (typeof nodeTypeParams === 'undefined') {
return false;
}

return nodeTypeParams.type === 'TSTypeParameterInstantiation';
}

function getGenericNode(node) {
Expand Down
24 changes: 14 additions & 10 deletions lib/util/propTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,8 @@ module.exports = function propTypesInstructions(context, components, utils) {
typeName = node.typeName.name;
const leftMostName = getLeftMostTypeName(node.typeName);
const shouldTraverseTypeParams = genericReactTypesImport.has(leftMostName);
if (shouldTraverseTypeParams && node.typeParameters && node.typeParameters.length !== 0) {
const nodeTypeParams = node.typeParameters;
if (shouldTraverseTypeParams && nodeTypeParams && nodeTypeParams.length !== 0) {
// All react Generic types are derived from:
// type PropsWithChildren<P> = P & { children?: ReactNode | undefined }
// So we should construct an optional children prop
Expand All @@ -638,7 +639,7 @@ module.exports = function propTypesInstructions(context, components, utils) {
const idx = genericTypeParamIndexWherePropsArePresent[
leftMostName !== rightMostName ? rightMostName : importedName
];
const nextNode = node.typeParameters.params[idx];
const nextNode = nodeTypeParams.params[idx];
this.visitTSNode(nextNode);
return;
}
Expand Down Expand Up @@ -727,9 +728,10 @@ module.exports = function propTypesInstructions(context, components, utils) {

convertReturnTypeToPropTypes(node) {
// ReturnType<T> should always have one parameter
if (node.typeParameters) {
if (node.typeParameters.params.length === 1) {
let returnType = node.typeParameters.params[0];
const nodeTypeParams = node.typeParameters;
if (nodeTypeParams) {
if (nodeTypeParams.params.length === 1) {
let returnType = nodeTypeParams.params[0];
// This line is trying to handle typescript-eslint-parser
// typescript-eslint-parser TSTypeQuery is wrapped by TSTypeReference
if (astUtil.isTSTypeReference(returnType)) {
Expand Down Expand Up @@ -761,8 +763,9 @@ module.exports = function propTypesInstructions(context, components, utils) {
case 'ObjectExpression':
iterateProperties(context, res.properties, (key, value, propNode) => {
if (propNode && propNode.argument && propNode.argument.type === 'CallExpression') {
if (propNode.argument.typeParameters) {
this.visitTSNode(propNode.argument.typeParameters);
const propNodeTypeParams = propNode.argument.typeParameters;
if (propNodeTypeParams) {
this.visitTSNode(propNodeTypeParams);
} else {
// Ignore this CallExpression return value since it doesn't have any typeParameters to let us know it's types.
this.shouldIgnorePropTypes = true;
Expand Down Expand Up @@ -960,8 +963,9 @@ module.exports = function propTypesInstructions(context, components, utils) {
break;
case 'GenericTypeAnnotation':
if (propTypes.id.name === '$ReadOnly') {
const propTypeParams = propTypes.typeParameters;
ignorePropsValidation = declarePropTypesForObjectTypeAnnotation(
propTypes.typeParameters.params[0],
propTypeParams.params[0],
declaredPropTypes
);
} else {
Expand Down Expand Up @@ -1011,9 +1015,9 @@ module.exports = function propTypesInstructions(context, components, utils) {
)
)
) {
const propTypes = node.parent.typeParameters.params[1];
const propTypesParams = node.parent.typeParameters;
const declaredPropTypes = {};
const obj = new DeclarePropTypesForTSTypeAnnotation(propTypes, declaredPropTypes);
const obj = new DeclarePropTypesForTSTypeAnnotation(propTypesParams.params[1], declaredPropTypes);
components.set(node, {
declaredPropTypes: obj.declaredPropTypes,
ignorePropsValidation: obj.shouldIgnorePropTypes,
Expand Down