Skip to content

Commit 30bb5f4

Browse files
HenryBrown0ljharb
authored andcommitted
[Fix] function-component-definition, boolean-prop-naming, jsx-first-prop-new-line, jsx-props-no-multi-spaces, propTypes: use type args
1 parent c4fcff9 commit 30bb5f4

7 files changed

+64
-36
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# Change Log
2+
23
All notable changes to this project will be documented in this file.
34
This project adheres to [Semantic Versioning](https://semver.org/).
45
This change log adheres to standards from [Keep a CHANGELOG](https://keepachangelog.com).
@@ -8,6 +9,9 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
89
### Added
910
* [`no-string-refs`]: allow this.refs in > 18.3.0 ([#3807][] @henryqdineen)
1011

12+
### Fixed
13+
* [`function-component-definition`], [`boolean-prop-naming`], [`jsx-first-prop-new-line`], [`jsx-props-no-multi-spaces`], `propTypes`: use type args ([#3629][] @HenryBrown0)
14+
1115
### Changed
1216
* [Tests] add @typescript-eslint/parser v6 ([#3629][] @HenryBrown0)
1317
* [Tests] add @typescript-eslint/parser v7 and v8 ([#3629][] @hampustagerud)

lib/rules/boolean-prop-naming.js

+7-5
Original file line numberDiff line numberDiff line change
@@ -259,14 +259,16 @@ module.exports = {
259259
return;
260260
}
261261

262-
const annotationTypeParams = component.node.parent.id.typeAnnotation.typeAnnotation.typeParameters;
262+
const annotationTypeArguments = propsUtil.getTypeArguments(
263+
component.node.parent.id.typeAnnotation.typeAnnotation
264+
);
263265
if (
264-
annotationTypeParams && (
265-
annotationTypeParams.type === 'TSTypeParameterInstantiation'
266-
|| annotationTypeParams.type === 'TypeParameterInstantiation'
266+
annotationTypeArguments && (
267+
annotationTypeArguments.type === 'TSTypeParameterInstantiation'
268+
|| annotationTypeArguments.type === 'TypeParameterInstantiation'
267269
)
268270
) {
269-
return annotationTypeParams.params.find(
271+
return annotationTypeArguments.params.find(
270272
(param) => param.type === 'TSTypeReference' || param.type === 'GenericTypeAnnotation'
271273
);
272274
}

lib/rules/function-component-definition.js

+8-6
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const Components = require('../util/Components');
1010
const docsUrl = require('../util/docsUrl');
1111
const reportC = require('../util/report');
1212
const getText = require('../util/eslint').getText;
13+
const propsUtil = require('../util/props');
1314

1415
// ------------------------------------------------------------------------------
1516
// Rule Definition
@@ -34,12 +35,12 @@ const UNNAMED_FUNCTION_TEMPLATES = {
3435
};
3536

3637
function hasOneUnconstrainedTypeParam(node) {
37-
const nodeTypeParams = node.typeParameters;
38+
const nodeTypeArguments = propsUtil.getTypeArguments(node);
3839

39-
return nodeTypeParams
40-
&& nodeTypeParams.params
41-
&& nodeTypeParams.params.length === 1
42-
&& !nodeTypeParams.params[0].constraint;
40+
return nodeTypeArguments
41+
&& nodeTypeArguments.params
42+
&& nodeTypeArguments.params.length === 1
43+
&& !nodeTypeArguments.params[0].constraint;
4344
}
4445

4546
function hasName(node) {
@@ -202,11 +203,12 @@ module.exports = {
202203
varType = node.parent.parent.kind;
203204
}
204205

206+
const nodeTypeArguments = propsUtil.getTypeArguments(node);
205207
return (fixer) => fixer.replaceTextRange(
206208
options.range,
207209
buildFunction(options.template, {
208210
typeAnnotation,
209-
typeParams: getNodeText(node.typeParameters, source),
211+
typeParams: getNodeText(nodeTypeArguments, source),
210212
params: getParams(node, source),
211213
returnType: getNodeText(node.returnType, source),
212214
body: getBody(node, source),

lib/rules/jsx-first-prop-new-line.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
const docsUrl = require('../util/docsUrl');
99
const report = require('../util/report');
10+
const propsUtil = require('../util/props');
1011

1112
// ------------------------------------------------------------------------------
1213
// Rule Definition
@@ -55,7 +56,8 @@ module.exports = {
5556
report(context, messages.propOnNewLine, 'propOnNewLine', {
5657
node: decl,
5758
fix(fixer) {
58-
return fixer.replaceTextRange([(node.typeParameters || node.name).range[1], decl.range[0]], '\n');
59+
const nodeTypeArguments = propsUtil.getTypeArguments(node);
60+
return fixer.replaceTextRange([(nodeTypeArguments || node.name).range[1], decl.range[0]], '\n');
5961
},
6062
});
6163
}

lib/rules/jsx-props-no-multi-spaces.js

+6-5
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
const docsUrl = require('../util/docsUrl');
99
const eslintUtil = require('../util/eslint');
1010
const report = require('../util/report');
11+
const propsUtil = require('../util/props');
1112

1213
const getSourceCode = eslintUtil.getSourceCode;
1314
const getText = eslintUtil.getText;
@@ -103,26 +104,26 @@ module.exports = {
103104
}
104105

105106
function containsGenericType(node) {
106-
const nodeTypeParams = node.typeParameters;
107-
if (typeof nodeTypeParams === 'undefined') {
107+
const nodeTypeArguments = propsUtil.getTypeArguments(node);
108+
if (typeof nodeTypeArguments === 'undefined') {
108109
return false;
109110
}
110111

111-
return nodeTypeParams.type === 'TSTypeParameterInstantiation';
112+
return nodeTypeArguments.type === 'TSTypeParameterInstantiation';
112113
}
113114

114115
function getGenericNode(node) {
115116
const name = node.name;
116117
if (containsGenericType(node)) {
117-
const type = node.typeParameters;
118+
const nodeTypeArguments = propsUtil.getTypeArguments(node);
118119

119120
return Object.assign(
120121
{},
121122
node,
122123
{
123124
range: [
124125
name.range[0],
125-
type.range[1],
126+
nodeTypeArguments.range[1],
126127
],
127128
}
128129
);

lib/util/propTypes.js

+23-19
Original file line numberDiff line numberDiff line change
@@ -639,8 +639,8 @@ module.exports = function propTypesInstructions(context, components, utils) {
639639
typeName = node.typeName.name;
640640
const leftMostName = getLeftMostTypeName(node.typeName);
641641
const shouldTraverseTypeParams = genericReactTypesImport.has(leftMostName);
642-
const nodeTypeParams = node.typeParameters;
643-
if (shouldTraverseTypeParams && nodeTypeParams && nodeTypeParams.length !== 0) {
642+
const nodeTypeArguments = propsUtil.getTypeArguments(node);
643+
if (shouldTraverseTypeParams && nodeTypeArguments && nodeTypeArguments.length !== 0) {
644644
// All react Generic types are derived from:
645645
// type PropsWithChildren<P> = P & { children?: ReactNode | undefined }
646646
// So we should construct an optional children prop
@@ -662,7 +662,7 @@ module.exports = function propTypesInstructions(context, components, utils) {
662662
const idx = genericTypeParamIndexWherePropsArePresent[
663663
leftMostName !== rightMostName ? rightMostName : importedName
664664
];
665-
const nextNode = nodeTypeParams.params[idx];
665+
const nextNode = nodeTypeArguments.params[idx];
666666
this.visitTSNode(nextNode);
667667
return;
668668
}
@@ -759,10 +759,10 @@ module.exports = function propTypesInstructions(context, components, utils) {
759759

760760
convertReturnTypeToPropTypes(node, rootNode) {
761761
// ReturnType<T> should always have one parameter
762-
const nodeTypeParams = node.typeParameters;
763-
if (nodeTypeParams) {
764-
if (nodeTypeParams.params.length === 1) {
765-
let returnType = nodeTypeParams.params[0];
762+
const nodeTypeArguments = propsUtil.getTypeArguments(node);
763+
if (nodeTypeArguments) {
764+
if (nodeTypeArguments.params.length === 1) {
765+
let returnType = nodeTypeArguments.params[0];
766766
// This line is trying to handle typescript-eslint-parser
767767
// typescript-eslint-parser TSTypeQuery is wrapped by TSTypeReference
768768
if (astUtil.isTSTypeReference(returnType)) {
@@ -794,9 +794,9 @@ module.exports = function propTypesInstructions(context, components, utils) {
794794
case 'ObjectExpression':
795795
iterateProperties(context, res.properties, (key, value, propNode) => {
796796
if (propNode && astUtil.isCallExpression(propNode.argument)) {
797-
const propNodeTypeParams = propNode.argument.typeParameters;
798-
if (propNodeTypeParams) {
799-
this.visitTSNode(propNodeTypeParams);
797+
const propNodeTypeArguments = propsUtil.getTypeArguments(propNode.argument);
798+
if (propNodeTypeArguments) {
799+
this.visitTSNode(propNodeTypeArguments);
800800
} else {
801801
// Ignore this CallExpression return value since it doesn't have any typeParameters to let us know it's types.
802802
this.shouldIgnorePropTypes = true;
@@ -816,8 +816,8 @@ module.exports = function propTypesInstructions(context, components, utils) {
816816
});
817817
break;
818818
case 'CallExpression':
819-
if (res.typeParameters) {
820-
this.visitTSNode(res.typeParameters);
819+
if (propsUtil.getTypeArguments(res)) {
820+
this.visitTSNode(propsUtil.getTypeArguments(res));
821821
} else {
822822
// Ignore this CallExpression return value since it doesn't have any typeParameters to let us know it's types.
823823
this.shouldIgnorePropTypes = true;
@@ -1002,9 +1002,9 @@ module.exports = function propTypesInstructions(context, components, utils) {
10021002
break;
10031003
case 'GenericTypeAnnotation':
10041004
if (propTypes.id.name === '$ReadOnly') {
1005-
const propTypeParams = propTypes.typeParameters;
1005+
const propTypeArguments = propsUtil.getTypeArguments(propTypes);
10061006
ignorePropsValidation = declarePropTypesForObjectTypeAnnotation(
1007-
propTypeParams.params[0],
1007+
propTypeArguments.params[0],
10081008
declaredPropTypes
10091009
);
10101010
} else {
@@ -1041,11 +1041,16 @@ module.exports = function propTypesInstructions(context, components, utils) {
10411041
return;
10421042
}
10431043

1044+
let propTypesArguments = null;
1045+
if (node.parent) {
1046+
propTypesArguments = propsUtil.getTypeArguments(node.parent);
1047+
}
1048+
10441049
if (
10451050
node.parent
10461051
&& node.parent.callee
1047-
&& node.parent.typeParameters
1048-
&& node.parent.typeParameters.params
1052+
&& propTypesArguments
1053+
&& propTypesArguments.params
10491054
&& (
10501055
node.parent.callee.name === 'forwardRef' || (
10511056
node.parent.callee.object
@@ -1055,9 +1060,8 @@ module.exports = function propTypesInstructions(context, components, utils) {
10551060
)
10561061
)
10571062
) {
1058-
const propTypesParams = node.parent.typeParameters;
10591063
const declaredPropTypes = {};
1060-
const obj = new DeclarePropTypesForTSTypeAnnotation(propTypesParams.params[1], declaredPropTypes, rootNode);
1064+
const obj = new DeclarePropTypesForTSTypeAnnotation(propTypesArguments.params[1], declaredPropTypes, rootNode);
10611065
components.set(node, {
10621066
declaredPropTypes: obj.declaredPropTypes,
10631067
ignorePropsValidation: obj.shouldIgnorePropTypes,
@@ -1103,7 +1107,7 @@ module.exports = function propTypesInstructions(context, components, utils) {
11031107
if (
11041108
annotation
11051109
&& annotation.type !== 'TSTypeReference'
1106-
&& annotation.typeParameters == null
1110+
&& propsUtil.getTypeArguments(annotation) == null
11071111
) {
11081112
return;
11091113
}

lib/util/props.js

+13
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,18 @@ function isRequiredPropType(propTypeExpression) {
9393
&& propTypeExpression.property.name === 'isRequired';
9494
}
9595

96+
/**
97+
* Returns the type arguments of a node or type parameters if type arguments are not available.
98+
* @param {ASTNode} node The node to get the type arguments from.
99+
* @returns {ASTNode} The type arguments or type parameters of the node.
100+
*/
101+
function getTypeArguments(node) {
102+
if ('typeArguments' in node) {
103+
return node.typeArguments;
104+
}
105+
return node.typeParameters;
106+
}
107+
96108
module.exports = {
97109
isPropTypesDeclaration,
98110
isContextTypesDeclaration,
@@ -101,4 +113,5 @@ module.exports = {
101113
isDefaultPropsDeclaration,
102114
isDisplayNameDeclaration,
103115
isRequiredPropType,
116+
getTypeArguments,
104117
};

0 commit comments

Comments
 (0)