β¬ οΈ Back to Table of Contents
π no-unnecessary-parameter-property-assignment¶
π Analysis Summary¶
| Metric | Count |
|---|---|
| π§ Functions | 10 |
| π¦ Imports | 7 |
| π Variables & Constants | 1 |
π Table of Contents¶
π οΈ File Location:¶
π packages/eslint-plugin/src/rules/no-unnecessary-parameter-property-assignment.ts
π€ Default Export¶
| Property | Value |
|---|---|
name |
'no-unnecessary-parameter-property-assignment' |
meta.type |
'suggestion' |
meta.docs.description |
'Disallow unnecessary assignment of constructor property parameter' |
meta.messages.unnecessaryAssign |
'This assignment is unnecessary since it is already assigned by a parameter property.' |
meta.schema |
[] |
defaultOptions |
[] |
Entry point: create β documented under Functions.
π¦ Imports¶
| Name | Source |
|---|---|
TSESTree |
@typescript-eslint/utils |
DefinitionType |
@typescript-eslint/scope-manager |
AST_NODE_TYPES |
@typescript-eslint/utils |
ASTUtils |
@typescript-eslint/utils |
createRule |
../util |
getStaticStringValue |
../util |
nullThrows |
../util |
Variables & Constants¶
| Name | Type | Kind | Value | Exported |
|---|---|---|---|---|
UNNECESSARY_OPERATORS |
Set<string> |
const | new Set(['??=', '&&=', '=', '\|\|=']) |
β |
Functions¶
create(context: any): { ClassBody(): void; 'ClassBody:exit'(): void; "MethodDefin⦶
Parameters:
contextany
Returns: { ClassBody(): void; 'ClassBody:exit'(): void; "MethodDefinition[kind='constructor'] > FunctionExpression AssignmentExpression"(node: TSESTree.AssignmentExpression): void; 'PropertyDefinition AssignmentExpression'(node: TSESTree.AssignmentExpression): void; }
Calls:
isThisMemberExpressiongetStaticStringValue (from ../util)findParentFunctionfindParentPropertyDefinitionASTUtils.isConstructorcontext.sourceCode.getScopescope.references.findrightRef?.resolved?.defs.atgetIdentifierreportInfoStack.pushnullThrows (from ../util)reportInfoStack.popunnecessaryAssignments.forEachassignedBeforeConstructor.hascontext.reportgetPropertyNameisArrowIIFEisConstructorFunctionExpressionreportInfoStack.atUNNECESSARY_OPERATORS.hasassignedBeforeUnnecessary.addisReferenceFromParameterfunctionNode.params.someisParameterPropertyWithNameassignedBeforeUnnecessary.hasunnecessaryAssignments.pushassignedBeforeConstructor.add
Code
create(context) {
const reportInfoStack: {
assignedBeforeConstructor: Set<string>;
assignedBeforeUnnecessary: Set<string>;
unnecessaryAssignments: {
name: string;
node: TSESTree.AssignmentExpression;
}[];
}[] = [];
function isThisMemberExpression(
node: TSESTree.Node,
): node is TSESTree.MemberExpression {
return (
node.type === AST_NODE_TYPES.MemberExpression &&
node.object.type === AST_NODE_TYPES.ThisExpression
);
}
function getPropertyName(node: TSESTree.Node): string | null {
if (!isThisMemberExpression(node)) {
return null;
}
if (!node.computed && node.property.type === AST_NODE_TYPES.Identifier) {
return node.property.name;
}
if (node.computed) {
return getStaticStringValue(node.property);
}
return null;
}
function findParentFunction(
node: TSESTree.Node | undefined,
):
| TSESTree.ArrowFunctionExpression
| TSESTree.FunctionDeclaration
| TSESTree.FunctionExpression
| undefined {
if (
!node ||
node.type === AST_NODE_TYPES.FunctionDeclaration ||
node.type === AST_NODE_TYPES.FunctionExpression ||
node.type === AST_NODE_TYPES.ArrowFunctionExpression
) {
return node;
}
return findParentFunction(node.parent);
}
function findParentPropertyDefinition(
node: TSESTree.Node | undefined,
): TSESTree.PropertyDefinition | undefined {
if (!node || node.type === AST_NODE_TYPES.PropertyDefinition) {
return node;
}
return findParentPropertyDefinition(node.parent);
}
function isConstructorFunctionExpression(
node: TSESTree.Node | undefined,
): node is TSESTree.FunctionExpression {
return (
node?.type === AST_NODE_TYPES.FunctionExpression &&
ASTUtils.isConstructor(node.parent)
);
}
function isReferenceFromParameter(node: TSESTree.Identifier): boolean {
const scope = context.sourceCode.getScope(node);
const rightRef = scope.references.find(
ref => ref.identifier.name === node.name,
);
return rightRef?.resolved?.defs.at(0)?.type === DefinitionType.Parameter;
}
function isParameterPropertyWithName(
node: TSESTree.Parameter,
name: string,
): boolean {
return (
node.type === AST_NODE_TYPES.TSParameterProperty &&
((node.parameter.type === AST_NODE_TYPES.Identifier && // constructor (public foo) {}
node.parameter.name === name) ||
(node.parameter.type === AST_NODE_TYPES.AssignmentPattern && // constructor (public foo = 1) {}
node.parameter.left.name === name))
);
}
function getIdentifier(node: TSESTree.Node): TSESTree.Identifier | null {
if (node.type === AST_NODE_TYPES.Identifier) {
return node;
}
if (
node.type === AST_NODE_TYPES.TSAsExpression ||
node.type === AST_NODE_TYPES.TSNonNullExpression
) {
return getIdentifier(node.expression);
}
return null;
}
function isArrowIIFE(node: TSESTree.Node): boolean {
return (
node.type === AST_NODE_TYPES.ArrowFunctionExpression &&
node.parent.type === AST_NODE_TYPES.CallExpression
);
}
return {
ClassBody(): void {
reportInfoStack.push({
assignedBeforeConstructor: new Set(),
assignedBeforeUnnecessary: new Set(),
unnecessaryAssignments: [],
});
},
'ClassBody:exit'(): void {
const { assignedBeforeConstructor, unnecessaryAssignments } =
nullThrows(reportInfoStack.pop(), 'The top stack should exist');
unnecessaryAssignments.forEach(({ name, node }) => {
if (assignedBeforeConstructor.has(name)) {
return;
}
context.report({
node,
messageId: 'unnecessaryAssign',
});
});
},
"MethodDefinition[kind='constructor'] > FunctionExpression AssignmentExpression"(
node: TSESTree.AssignmentExpression,
): void {
const leftName = getPropertyName(node.left);
if (!leftName) {
return;
}
let functionNode = findParentFunction(node);
if (functionNode && isArrowIIFE(functionNode)) {
functionNode = findParentFunction(functionNode.parent);
}
if (!isConstructorFunctionExpression(functionNode)) {
return;
}
const { assignedBeforeUnnecessary, unnecessaryAssignments } =
nullThrows(
reportInfoStack.at(reportInfoStack.length - 1),
'The top of stack should exist',
);
if (!UNNECESSARY_OPERATORS.has(node.operator)) {
assignedBeforeUnnecessary.add(leftName);
return;
}
const rightId = getIdentifier(node.right);
if (leftName !== rightId?.name || !isReferenceFromParameter(rightId)) {
return;
}
const hasParameterProperty = functionNode.params.some(param =>
isParameterPropertyWithName(param, rightId.name),
);
if (hasParameterProperty && !assignedBeforeUnnecessary.has(leftName)) {
unnecessaryAssignments.push({
name: leftName,
node,
});
}
},
'PropertyDefinition AssignmentExpression'(
node: TSESTree.AssignmentExpression,
): void {
const name = getPropertyName(node.left);
if (!name) {
return;
}
const functionNode = findParentFunction(node);
if (
functionNode &&
!(
isArrowIIFE(functionNode) &&
findParentPropertyDefinition(node)?.value === functionNode.parent
)
) {
return;
}
const { assignedBeforeConstructor } = nullThrows(
reportInfoStack.at(-1),
'The top stack should exist',
);
assignedBeforeConstructor.add(name);
},
};
}
Internal helpers¶
Declared inside another function in this file.
isThisMemberExpression(node: TSESTree.Node): node is TSESTree.MemberExpression¶
Parameters:
nodeTSESTree.Node
Returns: node is TSESTree.MemberExpression
Code
getPropertyName(node: TSESTree.Node): string | null¶
Parameters:
nodeTSESTree.Node
Returns: string | null
Calls:
isThisMemberExpressiongetStaticStringValue (from ../util)
Code
findParentFunction(node: TSESTree.Node | undefined): | TSESTree.ArrowFunctionExpression | TSESTree.FunctionDecla⦶
Parameters:
nodeTSESTree.Node | undefined
Returns: | TSESTree.ArrowFunctionExpression
| TSESTree.FunctionDeclaration
| TSESTree.FunctionExpression
| undefined
Calls:
findParentFunction
Code
function findParentFunction(
node: TSESTree.Node | undefined,
):
| TSESTree.ArrowFunctionExpression
| TSESTree.FunctionDeclaration
| TSESTree.FunctionExpression
| undefined {
if (
!node ||
node.type === AST_NODE_TYPES.FunctionDeclaration ||
node.type === AST_NODE_TYPES.FunctionExpression ||
node.type === AST_NODE_TYPES.ArrowFunctionExpression
) {
return node;
}
return findParentFunction(node.parent);
}
findParentPropertyDefinition(node: TSESTree.Node | undefined): TSESTree.PropertyDefinition | undefined¶
Parameters:
nodeTSESTree.Node | undefined
Returns: TSESTree.PropertyDefinition | undefined
Calls:
findParentPropertyDefinition
Code
isConstructorFunctionExpression(node: TSESTree.Node | undefined): node is TSESTree.FunctionExpression¶
Parameters:
nodeTSESTree.Node | undefined
Returns: node is TSESTree.FunctionExpression
Calls:
ASTUtils.isConstructor
Code
isReferenceFromParameter(node: TSESTree.Identifier): boolean¶
Parameters:
nodeTSESTree.Identifier
Returns: boolean
Calls:
context.sourceCode.getScopescope.references.findrightRef?.resolved?.defs.at
Code
isParameterPropertyWithName(node: TSESTree.Parameter, name: string): boolean¶
Parameters:
nodeTSESTree.Parameternamestring
Returns: boolean
Code
function isParameterPropertyWithName(
node: TSESTree.Parameter,
name: string,
): boolean {
return (
node.type === AST_NODE_TYPES.TSParameterProperty &&
((node.parameter.type === AST_NODE_TYPES.Identifier && // constructor (public foo) {}
node.parameter.name === name) ||
(node.parameter.type === AST_NODE_TYPES.AssignmentPattern && // constructor (public foo = 1) {}
node.parameter.left.name === name))
);
}
getIdentifier(node: TSESTree.Node): TSESTree.Identifier | null¶
Parameters:
nodeTSESTree.Node
Returns: TSESTree.Identifier | null
Calls:
getIdentifier
Code
isArrowIIFE(node: TSESTree.Node): boolean¶
Parameters:
nodeTSESTree.Node
Returns: boolean
Code
Generated by Syntax Scribe