diff --git a/packages/ast-spec/src/index.ts b/packages/ast-spec/src/index.ts index 3994016c2e0..3ca95ed6417 100644 --- a/packages/ast-spec/src/index.ts +++ b/packages/ast-spec/src/index.ts @@ -1,5 +1,6 @@ export * from './base/Accessibility'; export * from './base/BaseNode'; // this is exported so that the `types` package can merge the decl and add the `parent` property +export * from './base/NodeOrTokenData'; export * from './base/OptionalRangeAndLoc'; export * from './base/Position'; export * from './base/Range'; diff --git a/packages/ast-spec/src/special/Program/spec.ts b/packages/ast-spec/src/special/Program/spec.ts index 81d69e1e604..8d84824f563 100644 --- a/packages/ast-spec/src/special/Program/spec.ts +++ b/packages/ast-spec/src/special/Program/spec.ts @@ -1,10 +1,10 @@ import type { AST_NODE_TYPES } from '../../ast-node-types'; -import type { BaseNode } from '../../base/BaseNode'; +import type { NodeOrTokenData } from '../../base/NodeOrTokenData'; import type { Comment } from '../../unions/Comment'; import type { ProgramStatement } from '../../unions/Statement'; import type { Token } from '../../unions/Token'; -export interface Program extends BaseNode { +export interface Program extends NodeOrTokenData { type: AST_NODE_TYPES.Program; body: ProgramStatement[]; sourceType: 'module' | 'script'; diff --git a/packages/eslint-plugin/src/rules/array-type.ts b/packages/eslint-plugin/src/rules/array-type.ts index 92040d8106a..e4ae8498183 100644 --- a/packages/eslint-plugin/src/rules/array-type.ts +++ b/packages/eslint-plugin/src/rules/array-type.ts @@ -154,7 +154,6 @@ export default util.createRule({ return { TSArrayType(node): void { const isReadonly = - node.parent && node.parent.type === AST_NODE_TYPES.TSTypeOperator && node.parent.operator === 'readonly'; @@ -171,7 +170,7 @@ export default util.createRule({ currentOption === 'generic' ? 'errorStringGeneric' : 'errorStringGenericSimple'; - const errorNode = isReadonly ? node.parent! : node; + const errorNode = isReadonly ? node.parent : node; context.report({ node: errorNode, diff --git a/packages/eslint-plugin/src/rules/consistent-generic-constructors.ts b/packages/eslint-plugin/src/rules/consistent-generic-constructors.ts index 3524da30859..a024a50e600 100644 --- a/packages/eslint-plugin/src/rules/consistent-generic-constructors.ts +++ b/packages/eslint-plugin/src/rules/consistent-generic-constructors.ts @@ -96,7 +96,7 @@ export default createRule({ const hasParens = sourceCode.getTokenAfter(rhs.callee)?.value === '('; const extraComments = new Set( - sourceCode.getCommentsInside(lhs.parent!), + sourceCode.getCommentsInside(lhs.parent), ); sourceCode .getCommentsInside(lhs.typeParameters) @@ -105,7 +105,7 @@ export default createRule({ node, messageId: 'preferConstructor', *fix(fixer) { - yield fixer.remove(lhs.parent!); + yield fixer.remove(lhs.parent); for (const comment of extraComments) { yield fixer.insertTextAfter( rhs.callee, diff --git a/packages/eslint-plugin/src/rules/consistent-type-assertions.ts b/packages/eslint-plugin/src/rules/consistent-type-assertions.ts index 66268b0adc6..41f255dea83 100644 --- a/packages/eslint-plugin/src/rules/consistent-type-assertions.ts +++ b/packages/eslint-plugin/src/rules/consistent-type-assertions.ts @@ -134,7 +134,6 @@ export default util.createRule({ if ( options.objectLiteralTypeAssertions === 'allow-as-parameter' && - node.parent && (node.parent.type === AST_NODE_TYPES.NewExpression || node.parent.type === AST_NODE_TYPES.CallExpression || node.parent.type === AST_NODE_TYPES.ThrowStatement || diff --git a/packages/eslint-plugin/src/rules/explicit-module-boundary-types.ts b/packages/eslint-plugin/src/rules/explicit-module-boundary-types.ts index b891cbec6cb..669d85968a5 100644 --- a/packages/eslint-plugin/src/rules/explicit-module-boundary-types.ts +++ b/packages/eslint-plugin/src/rules/explicit-module-boundary-types.ts @@ -269,7 +269,7 @@ export default util.createRule({ } function isExportedHigherOrderFunction(node: FunctionNode): boolean { - let current = node.parent; + let current: TSESTree.Node | undefined = node.parent; while (current) { if (current.type === AST_NODE_TYPES.ReturnStatement) { // the parent of a return will always be a block statement, so we can skip over it diff --git a/packages/eslint-plugin/src/rules/indent.ts b/packages/eslint-plugin/src/rules/indent.ts index 19796054a4c..4973a790212 100644 --- a/packages/eslint-plugin/src/rules/indent.ts +++ b/packages/eslint-plugin/src/rules/indent.ts @@ -210,6 +210,7 @@ export default util.createRule({ return rules.ConditionalExpression({ type: AST_NODE_TYPES.ConditionalExpression, test: { + parent: node, type: AST_NODE_TYPES.BinaryExpression, operator: 'extends', left: node.checkType as any, @@ -371,6 +372,7 @@ export default util.createRule({ type: AST_NODE_TYPES.ObjectExpression, properties: [ { + parent: node, type: AST_NODE_TYPES.Property, key: node.typeParameter as any, value: node.typeAnnotation as any, diff --git a/packages/eslint-plugin/src/rules/init-declarations.ts b/packages/eslint-plugin/src/rules/init-declarations.ts index 27bdf3c75a5..04f7a1a262e 100644 --- a/packages/eslint-plugin/src/rules/init-declarations.ts +++ b/packages/eslint-plugin/src/rules/init-declarations.ts @@ -49,7 +49,7 @@ export default createRule({ function isAncestorNamespaceDeclared( node: TSESTree.VariableDeclaration, ): boolean { - let ancestor = node.parent; + let ancestor: TSESTree.Node | undefined = node.parent; while (ancestor) { if ( diff --git a/packages/eslint-plugin/src/rules/no-base-to-string.ts b/packages/eslint-plugin/src/rules/no-base-to-string.ts index 8b8521491f2..e2eb948b271 100644 --- a/packages/eslint-plugin/src/rules/no-base-to-string.ts +++ b/packages/eslint-plugin/src/rules/no-base-to-string.ts @@ -178,10 +178,7 @@ export default util.createRule({ checkExpression(memberExpr.object); }, TemplateLiteral(node: TSESTree.TemplateLiteral): void { - if ( - node.parent && - node.parent.type === AST_NODE_TYPES.TaggedTemplateExpression - ) { + if (node.parent.type === AST_NODE_TYPES.TaggedTemplateExpression) { return; } for (const expression of node.expressions) { diff --git a/packages/eslint-plugin/src/rules/no-confusing-void-expression.ts b/packages/eslint-plugin/src/rules/no-confusing-void-expression.ts index 01e5b45dbb8..32cc048d6a5 100644 --- a/packages/eslint-plugin/src/rules/no-confusing-void-expression.ts +++ b/packages/eslint-plugin/src/rules/no-confusing-void-expression.ts @@ -186,7 +186,7 @@ export default util.createRule({ // put a semicolon at the beginning of the line newReturnStmtText = `;${newReturnStmtText}`; } - if (returnStmt.parent?.type !== AST_NODE_TYPES.BlockStatement) { + if (returnStmt.parent.type !== AST_NODE_TYPES.BlockStatement) { // e.g. `if (cond) return console.error();` // add braces if not inside a block newReturnStmtText = `{ ${newReturnStmtText} }`; diff --git a/packages/eslint-plugin/src/rules/no-explicit-any.ts b/packages/eslint-plugin/src/rules/no-explicit-any.ts index 6823a3c7bcd..707f2148162 100644 --- a/packages/eslint-plugin/src/rules/no-explicit-any.ts +++ b/packages/eslint-plugin/src/rules/no-explicit-any.ts @@ -83,7 +83,6 @@ export default util.createRule({ function isNodeRestElementInFunction(node: TSESTree.Node): boolean { return ( node.type === AST_NODE_TYPES.RestElement && - typeof node.parent !== 'undefined' && isNodeValidFunction(node.parent) ); } diff --git a/packages/eslint-plugin/src/rules/no-extraneous-class.ts b/packages/eslint-plugin/src/rules/no-extraneous-class.ts index b7b93c8c77c..6982283e0c9 100644 --- a/packages/eslint-plugin/src/rules/no-extraneous-class.ts +++ b/packages/eslint-plugin/src/rules/no-extraneous-class.ts @@ -82,10 +82,9 @@ export default util.createRule({ ClassBody(node): void { const parent = node.parent as | TSESTree.ClassDeclaration - | TSESTree.ClassExpression - | undefined; + | TSESTree.ClassExpression; - if (!parent || parent.superClass || isAllowWithDecorator(parent)) { + if (parent.superClass || isAllowWithDecorator(parent)) { return; } diff --git a/packages/eslint-plugin/src/rules/no-invalid-void-type.ts b/packages/eslint-plugin/src/rules/no-invalid-void-type.ts index 9f938ac438f..ebfb1f53928 100644 --- a/packages/eslint-plugin/src/rules/no-invalid-void-type.ts +++ b/packages/eslint-plugin/src/rules/no-invalid-void-type.ts @@ -166,11 +166,6 @@ export default util.createRule<[Options], MessageIds>({ return { TSVoidKeyword(node: TSESTree.TSVoidKeyword): void { - /* istanbul ignore next */ - if (!node.parent?.parent) { - return; - } - // checks T<..., void, ...> against specification of allowInGenericArguments option if ( node.parent.type === AST_NODE_TYPES.TSTypeParameterInstantiation && @@ -211,7 +206,7 @@ export default util.createRule<[Options], MessageIds>({ // default cases if ( validParents.includes(node.parent.type) && - !invalidGrandParents.includes(node.parent.parent.type) + !invalidGrandParents.includes(node.parent.parent!.type) ) { return; } @@ -235,7 +230,7 @@ export default util.createRule<[Options], MessageIds>({ function getNotReturnOrGenericMessageId( node: TSESTree.TSVoidKeyword, ): MessageIds { - return node.parent!.type === AST_NODE_TYPES.TSUnionType + return node.parent.type === AST_NODE_TYPES.TSUnionType ? 'invalidVoidUnionConstituent' : 'invalidVoidNotReturnOrGeneric'; } diff --git a/packages/eslint-plugin/src/rules/no-misused-new.ts b/packages/eslint-plugin/src/rules/no-misused-new.ts index 7a4dcc69dab..236d1c544f9 100644 --- a/packages/eslint-plugin/src/rules/no-misused-new.ts +++ b/packages/eslint-plugin/src/rules/no-misused-new.ts @@ -70,7 +70,7 @@ export default util.createRule({ ): void { if ( isMatchingParentType( - node.parent!.parent as TSESTree.TSInterfaceDeclaration, + node.parent.parent as TSESTree.TSInterfaceDeclaration, node.returnType, ) ) { @@ -93,10 +93,7 @@ export default util.createRule({ node: TSESTree.MethodDefinition, ): void { if (node.value.type === AST_NODE_TYPES.TSEmptyBodyFunctionExpression) { - if ( - node.parent && - isMatchingParentType(node.parent.parent, node.value.returnType) - ) { + if (isMatchingParentType(node.parent.parent, node.value.returnType)) { context.report({ node, messageId: 'errorMessageClass', diff --git a/packages/eslint-plugin/src/rules/no-namespace.ts b/packages/eslint-plugin/src/rules/no-namespace.ts index 2a9a4a251be..40920077ab4 100644 --- a/packages/eslint-plugin/src/rules/no-namespace.ts +++ b/packages/eslint-plugin/src/rules/no-namespace.ts @@ -67,8 +67,7 @@ export default util.createRule({ node: TSESTree.TSModuleDeclaration, ): void { if ( - (node.parent && - node.parent.type === AST_NODE_TYPES.TSModuleDeclaration) || + node.parent.type === AST_NODE_TYPES.TSModuleDeclaration || (allowDefinitionFiles && util.isDefinitionFile(filename)) || (allowDeclarations && isDeclaration(node)) ) { diff --git a/packages/eslint-plugin/src/rules/no-redeclare.ts b/packages/eslint-plugin/src/rules/no-redeclare.ts index 2b10c97c8e7..5d223a35c47 100644 --- a/packages/eslint-plugin/src/rules/no-redeclare.ts +++ b/packages/eslint-plugin/src/rules/no-redeclare.ts @@ -103,7 +103,7 @@ export default util.createRule({ const identifiers = variable.identifiers .map(id => ({ identifier: id, - parent: id.parent!, + parent: id.parent, })) // ignore function declarations because TS will treat them as an overload .filter( diff --git a/packages/eslint-plugin/src/rules/no-redundant-type-constituents.ts b/packages/eslint-plugin/src/rules/no-redundant-type-constituents.ts index 33237a8ae4e..0055c5fe3f6 100644 --- a/packages/eslint-plugin/src/rules/no-redundant-type-constituents.ts +++ b/packages/eslint-plugin/src/rules/no-redundant-type-constituents.ts @@ -155,7 +155,6 @@ function describeLiteralTypeNode(typeNode: TSESTree.TypeNode): string { function isNodeInsideReturnType(node: TSESTree.TSUnionType): boolean { return !!( node.parent?.type === AST_NODE_TYPES.TSTypeAnnotation && - node.parent.parent && (util.isFunctionType(node.parent.parent) || util.isFunction(node.parent.parent)) ); diff --git a/packages/eslint-plugin/src/rules/no-unused-vars.ts b/packages/eslint-plugin/src/rules/no-unused-vars.ts index 5fcde198667..6ee751681c0 100644 --- a/packages/eslint-plugin/src/rules/no-unused-vars.ts +++ b/packages/eslint-plugin/src/rules/no-unused-vars.ts @@ -167,10 +167,10 @@ export default util.createRule({ ): boolean { if (options.ignoreRestSiblings) { const hasRestSiblingDefinition = variable.defs.some(def => - hasRestSibling(def.name.parent!), + hasRestSibling(def.name.parent), ); const hasRestSiblingReference = variable.references.some(ref => - hasRestSibling(ref.identifier.parent!), + hasRestSibling(ref.identifier.parent), ); return hasRestSiblingDefinition || hasRestSiblingReference; diff --git a/packages/eslint-plugin/src/rules/no-use-before-define.ts b/packages/eslint-plugin/src/rules/no-use-before-define.ts index 5153ed47fcd..d370d5b267e 100644 --- a/packages/eslint-plugin/src/rules/no-use-before-define.ts +++ b/packages/eslint-plugin/src/rules/no-use-before-define.ts @@ -116,9 +116,6 @@ function referenceContainsTypeQuery(node: TSESTree.Node): boolean { case AST_NODE_TYPES.TSQualifiedName: case AST_NODE_TYPES.Identifier: - if (!node.parent) { - return false; - } return referenceContainsTypeQuery(node.parent); default: @@ -196,7 +193,7 @@ function isInInitializer( return false; } - let node = variable.identifiers[0].parent; + let node: TSESTree.Node | undefined = variable.identifiers[0].parent; const location = reference.identifier.range[1]; while (node) { diff --git a/packages/eslint-plugin/src/rules/no-useless-constructor.ts b/packages/eslint-plugin/src/rules/no-useless-constructor.ts index b83b2706fc8..c37dd213621 100644 --- a/packages/eslint-plugin/src/rules/no-useless-constructor.ts +++ b/packages/eslint-plugin/src/rules/no-useless-constructor.ts @@ -19,9 +19,7 @@ function checkAccessibility(node: TSESTree.MethodDefinition): boolean { return false; case 'public': if ( - node.parent && node.parent.type === AST_NODE_TYPES.ClassBody && - node.parent.parent && 'superClass' in node.parent.parent && node.parent.parent.superClass ) { diff --git a/packages/eslint-plugin/src/rules/prefer-as-const.ts b/packages/eslint-plugin/src/rules/prefer-as-const.ts index b8cc483d6ee..00d1250d9ac 100644 --- a/packages/eslint-plugin/src/rules/prefer-as-const.ts +++ b/packages/eslint-plugin/src/rules/prefer-as-const.ts @@ -49,7 +49,7 @@ export default util.createRule({ { messageId: 'variableSuggest', fix: (fixer): TSESLint.RuleFix[] => [ - fixer.remove(typeNode.parent!), + fixer.remove(typeNode.parent), fixer.insertTextAfter(valueNode, ' as const'), ], }, diff --git a/packages/eslint-plugin/src/rules/prefer-function-type.ts b/packages/eslint-plugin/src/rules/prefer-function-type.ts index 95b3ee5d33b..747cd163865 100644 --- a/packages/eslint-plugin/src/rules/prefer-function-type.ts +++ b/packages/eslint-plugin/src/rules/prefer-function-type.ts @@ -99,7 +99,6 @@ export default util.createRule({ } const fixable = - node.parent && node.parent.type === AST_NODE_TYPES.ExportDefaultDeclaration; const fix = fixable @@ -137,7 +136,6 @@ export default util.createRule({ } const isParentExported = - node.parent && node.parent.type === AST_NODE_TYPES.ExportNamedDeclaration; if ( @@ -154,12 +152,7 @@ export default util.createRule({ ); }, ''); // comments should move before export and not between export and interface declaration - fixes.push( - fixer.insertTextBefore( - node.parent as TSESTree.Node | TSESTree.Token, - commentsText, - ), - ); + fixes.push(fixer.insertTextBefore(node.parent, commentsText)); } else { comments.forEach(comment => { let commentText = diff --git a/packages/eslint-plugin/src/rules/prefer-nullish-coalescing.ts b/packages/eslint-plugin/src/rules/prefer-nullish-coalescing.ts index f29df6f6f98..deba4340b04 100644 --- a/packages/eslint-plugin/src/rules/prefer-nullish-coalescing.ts +++ b/packages/eslint-plugin/src/rules/prefer-nullish-coalescing.ts @@ -111,7 +111,7 @@ export default util.createRule({ function* fix( fixer: TSESLint.RuleFixer, ): IterableIterator { - if (node.parent && util.isLogicalOrOperator(node.parent)) { + if (util.isLogicalOrOperator(node.parent)) { // '&&' and '??' operations cannot be mixed without parentheses (e.g. a && b ?? c) if ( node.left.type === AST_NODE_TYPES.LogicalExpression && diff --git a/packages/eslint-plugin/src/rules/prefer-optional-chain.ts b/packages/eslint-plugin/src/rules/prefer-optional-chain.ts index 73fbcc27af3..182b4c4ae68 100644 --- a/packages/eslint-plugin/src/rules/prefer-optional-chain.ts +++ b/packages/eslint-plugin/src/rules/prefer-optional-chain.ts @@ -122,7 +122,7 @@ export default util.createRule({ ): void { // selector guarantees this cast const initialExpression = ( - initialIdentifierOrNotEqualsExpr.parent!.type === + initialIdentifierOrNotEqualsExpr.parent.type === AST_NODE_TYPES.ChainExpression ? initialIdentifierOrNotEqualsExpr.parent.parent : initialIdentifierOrNotEqualsExpr.parent diff --git a/packages/eslint-plugin/src/rules/prefer-return-this-type.ts b/packages/eslint-plugin/src/rules/prefer-return-this-type.ts index 59a5c85b2bd..b6ea9d465bd 100644 --- a/packages/eslint-plugin/src/rules/prefer-return-this-type.ts +++ b/packages/eslint-plugin/src/rules/prefer-return-this-type.ts @@ -151,7 +151,7 @@ export default createRule({ return { 'ClassBody > MethodDefinition'(node: TSESTree.MethodDefinition): void { - checkFunction(node.value, node.parent!.parent as ClassLikeDeclaration); + checkFunction(node.value, node.parent.parent as ClassLikeDeclaration); }, 'ClassBody > PropertyDefinition'( node: TSESTree.PropertyDefinition, @@ -165,7 +165,7 @@ export default createRule({ return; } - checkFunction(node.value, node.parent!.parent as ClassLikeDeclaration); + checkFunction(node.value, node.parent.parent as ClassLikeDeclaration); }, }; }, diff --git a/packages/eslint-plugin/src/rules/promise-function-async.ts b/packages/eslint-plugin/src/rules/promise-function-async.ts index 4387bc52c9b..81765bc18b8 100644 --- a/packages/eslint-plugin/src/rules/promise-function-async.ts +++ b/packages/eslint-plugin/src/rules/promise-function-async.ts @@ -121,13 +121,12 @@ export default util.createRule({ return; } - if (node.parent?.type === AST_NODE_TYPES.TSAbstractMethodDefinition) { + if (node.parent.type === AST_NODE_TYPES.TSAbstractMethodDefinition) { // Abstract method can't be async return; } if ( - node.parent && (node.parent.type === AST_NODE_TYPES.Property || node.parent.type === AST_NODE_TYPES.MethodDefinition) && (node.parent.kind === 'get' || node.parent.kind === 'set') @@ -153,10 +152,8 @@ export default util.createRule({ loc: util.getFunctionHeadLoc(node, sourceCode), fix: fixer => { if ( - node.parent && - (node.parent.type === AST_NODE_TYPES.MethodDefinition || - (node.parent.type === AST_NODE_TYPES.Property && - node.parent.method)) + node.parent.type === AST_NODE_TYPES.MethodDefinition || + (node.parent.type === AST_NODE_TYPES.Property && node.parent.method) ) { // this function is a class method or object function property shorthand const method = node.parent; @@ -219,7 +216,6 @@ export default util.createRule({ node: TSESTree.FunctionExpression, ): void { if ( - node.parent && node.parent.type === AST_NODE_TYPES.MethodDefinition && node.parent.kind === 'method' ) { diff --git a/packages/eslint-plugin/src/rules/require-array-sort-compare.ts b/packages/eslint-plugin/src/rules/require-array-sort-compare.ts index b37490abc5a..b7b57e46705 100644 --- a/packages/eslint-plugin/src/rules/require-array-sort-compare.ts +++ b/packages/eslint-plugin/src/rules/require-array-sort-compare.ts @@ -78,7 +78,7 @@ export default util.createRule({ } if (util.isTypeArrayTypeOrUnionOfArrayTypes(calleeObjType, checker)) { - context.report({ node: callee.parent!, messageId: 'requireCompare' }); + context.report({ node: callee.parent, messageId: 'requireCompare' }); } }, }; diff --git a/packages/eslint-plugin/src/rules/restrict-template-expressions.ts b/packages/eslint-plugin/src/rules/restrict-template-expressions.ts index 382f8ce0137..83ee29d7ea5 100644 --- a/packages/eslint-plugin/src/rules/restrict-template-expressions.ts +++ b/packages/eslint-plugin/src/rules/restrict-template-expressions.ts @@ -117,7 +117,7 @@ export default util.createRule({ return { TemplateLiteral(node: TSESTree.TemplateLiteral): void { // don't check tagged template literals - if (node.parent!.type === AST_NODE_TYPES.TaggedTemplateExpression) { + if (node.parent.type === AST_NODE_TYPES.TaggedTemplateExpression) { return; } diff --git a/packages/eslint-plugin/src/rules/sort-type-union-intersection-members.ts b/packages/eslint-plugin/src/rules/sort-type-union-intersection-members.ts index 1fbf91b9ae8..a65f6c38e93 100644 --- a/packages/eslint-plugin/src/rules/sort-type-union-intersection-members.ts +++ b/packages/eslint-plugin/src/rules/sort-type-union-intersection-members.ts @@ -221,7 +221,7 @@ export default util.createRule({ ? 'Intersection' : 'Union', }; - if (node.parent?.type === AST_NODE_TYPES.TSTypeAliasDeclaration) { + if (node.parent.type === AST_NODE_TYPES.TSTypeAliasDeclaration) { messageId = 'notSortedNamed'; data.name = node.parent.id.name; } diff --git a/packages/eslint-plugin/src/rules/space-before-function-paren.ts b/packages/eslint-plugin/src/rules/space-before-function-paren.ts index 4a3f9042e78..792cb32f16f 100644 --- a/packages/eslint-plugin/src/rules/space-before-function-paren.ts +++ b/packages/eslint-plugin/src/rules/space-before-function-paren.ts @@ -79,7 +79,7 @@ export default util.createRule({ return true; } - const parent = node.parent!; + const parent = node.parent; return ( parent.type === AST_NODE_TYPES.MethodDefinition || diff --git a/packages/eslint-plugin/src/rules/strict-boolean-expressions.ts b/packages/eslint-plugin/src/rules/strict-boolean-expressions.ts index 1e327a8a4b8..74e6521eb66 100644 --- a/packages/eslint-plugin/src/rules/strict-boolean-expressions.ts +++ b/packages/eslint-plugin/src/rules/strict-boolean-expressions.ts @@ -508,7 +508,7 @@ export default util.createRule({ if (is('number') || is('truthy number')) { if (!options.allowNumber) { if (isArrayLengthExpression(node, typeChecker, parserServices)) { - if (isLogicalNegationExpression(node.parent!)) { + if (isLogicalNegationExpression(node.parent)) { // if (!array.length) context.report({ node, diff --git a/packages/eslint-plugin/src/rules/typedef.ts b/packages/eslint-plugin/src/rules/typedef.ts index dd1f6ed871b..0673566875c 100644 --- a/packages/eslint-plugin/src/rules/typedef.ts +++ b/packages/eslint-plugin/src/rules/typedef.ts @@ -154,7 +154,7 @@ export default util.createRule<[Options], MessageIds>({ function isAncestorHasTypeAnnotation( node: TSESTree.ObjectPattern | TSESTree.ArrayPattern, ): boolean { - let ancestor = node.parent; + let ancestor: TSESTree.Node | undefined = node.parent; while (ancestor) { if ( diff --git a/packages/eslint-plugin/src/rules/unified-signatures.ts b/packages/eslint-plugin/src/rules/unified-signatures.ts index 3e5d8fefb07..18d332d76f8 100644 --- a/packages/eslint-plugin/src/rules/unified-signatures.ts +++ b/packages/eslint-plugin/src/rules/unified-signatures.ts @@ -588,9 +588,8 @@ function getExportingNode( | TSESTree.ExportNamedDeclaration | TSESTree.ExportDefaultDeclaration | undefined { - return node.parent && - (node.parent.type === AST_NODE_TYPES.ExportNamedDeclaration || - node.parent.type === AST_NODE_TYPES.ExportDefaultDeclaration) + return node.parent.type === AST_NODE_TYPES.ExportNamedDeclaration || + node.parent.type === AST_NODE_TYPES.ExportDefaultDeclaration ? node.parent : undefined; } diff --git a/packages/eslint-plugin/src/util/collectUnusedVariables.ts b/packages/eslint-plugin/src/util/collectUnusedVariables.ts index ba3beb6861d..97b6386063d 100644 --- a/packages/eslint-plugin/src/util/collectUnusedVariables.ts +++ b/packages/eslint-plugin/src/util/collectUnusedVariables.ts @@ -321,7 +321,7 @@ class UnusedVarsVisitor< protected TSModuleDeclaration(node: TSESTree.TSModuleDeclaration): void { // -- global augmentation can be in any file, and they do not need exports if (node.global === true) { - this.markVariableAsUsed('global', node.parent!); + this.markVariableAsUsed('global', node.parent); } } @@ -561,7 +561,7 @@ function isUsedVariable(variable: TSESLint.Scope.Variable): boolean { } const id = ref.identifier; - const parent = id.parent!; + const parent = id.parent; const grandparent = parent.parent!; const refScope = ref.from.variableScope; const varScope = ref.resolved!.scope.variableScope; @@ -694,7 +694,7 @@ function isUsedVariable(variable: TSESLint.Scope.Variable): boolean { } const id = ref.identifier; - const parent = id.parent!; + const parent = id.parent; const grandparent = parent.parent!; return ( diff --git a/packages/eslint-plugin/src/util/explicitReturnTypeUtils.ts b/packages/eslint-plugin/src/util/explicitReturnTypeUtils.ts index 3ba5f4fac64..a47b101e07c 100644 --- a/packages/eslint-plugin/src/util/explicitReturnTypeUtils.ts +++ b/packages/eslint-plugin/src/util/explicitReturnTypeUtils.ts @@ -294,7 +294,7 @@ function checkFunctionExpressionReturnType( * Check whether any ancestor of the provided function has a valid return type. */ function ancestorHasReturnType(node: FunctionNode): boolean { - let ancestor = node.parent; + let ancestor: TSESTree.Node | undefined = node.parent; if (ancestor?.type === AST_NODE_TYPES.Property) { ancestor = ancestor.value; diff --git a/packages/eslint-plugin/src/util/getFunctionHeadLoc.ts b/packages/eslint-plugin/src/util/getFunctionHeadLoc.ts index 48c25b38f0d..e81d6ca8e62 100644 --- a/packages/eslint-plugin/src/util/getFunctionHeadLoc.ts +++ b/packages/eslint-plugin/src/util/getFunctionHeadLoc.ts @@ -28,7 +28,7 @@ export function getFunctionHeadLoc( sourceCode: TSESLint.SourceCode, ): TSESTree.SourceLocation { function getLocStart(): TSESTree.Position { - if (node.parent && node.parent.type === AST_NODE_TYPES.MethodDefinition) { + if (node.parent.type === AST_NODE_TYPES.MethodDefinition) { // return the start location for class method if (node.parent.decorators && node.parent.decorators.length > 0) { @@ -41,11 +41,7 @@ export function getFunctionHeadLoc( return node.parent.loc.start; } - if ( - node.parent && - node.parent.type === AST_NODE_TYPES.Property && - node.parent.method - ) { + if (node.parent.type === AST_NODE_TYPES.Property && node.parent.method) { // return the start location for object method shorthand return node.parent.loc.start; } diff --git a/packages/eslint-plugin/src/util/getWrappingFixer.ts b/packages/eslint-plugin/src/util/getWrappingFixer.ts index 0f867033b04..8f293f6ec17 100644 --- a/packages/eslint-plugin/src/util/getWrappingFixer.ts +++ b/packages/eslint-plugin/src/util/getWrappingFixer.ts @@ -136,7 +136,7 @@ function isMissingSemicolonBefore( const parent = node.parent!; if (parent.type === AST_NODE_TYPES.ExpressionStatement) { - const block = parent.parent!; + const block = parent.parent; if ( block.type === AST_NODE_TYPES.Program || block.type === AST_NODE_TYPES.BlockStatement diff --git a/packages/scope-manager/src/referencer/VisitorBase.ts b/packages/scope-manager/src/referencer/VisitorBase.ts index 5a7a8bbebe0..3432f35f5e2 100644 --- a/packages/scope-manager/src/referencer/VisitorBase.ts +++ b/packages/scope-manager/src/referencer/VisitorBase.ts @@ -35,11 +35,11 @@ abstract class VisitorBase { node: T | null | undefined, excludeArr: (keyof T)[] = [], ): void { - if (node == null || node.type == null) { + if (node?.type == null) { return; } - const exclude = new Set(excludeArr.concat(['parent'])) as Set; + const exclude = new Set([...excludeArr, 'parent'] as string[]); const children = this.#childVisitorKeys[node.type] ?? Object.keys(node); for (const key of children) { if (exclude.has(key)) { diff --git a/packages/types/src/ts-estree.ts b/packages/types/src/ts-estree.ts index 7ce3d0a674a..acfd90fb9a3 100644 --- a/packages/types/src/ts-estree.ts +++ b/packages/types/src/ts-estree.ts @@ -2,20 +2,16 @@ import type * as TSESTree from './generated/ast-spec'; // augment to add the parent property, which isn't part of the spec declare module './generated/ast-spec' { - interface BaseNode { - parent?: TSESTree.Node; - } - - // TODO - make this change as a breaking change - /* interface BaseNode { parent: TSESTree.Node; } interface Program { - parent?: undefined; + /** + * @remarks This never-used property exists only as a convenience for code that tries to access node parents repeatedly. + */ + parent?: never; } - */ } export * as TSESTree from './generated/ast-spec'; diff --git a/packages/typescript-estree/src/convert.ts b/packages/typescript-estree/src/convert.ts index 2bcf03e6193..2ad5ca9bad2 100644 --- a/packages/typescript-estree/src/convert.ts +++ b/packages/typescript-estree/src/convert.ts @@ -249,16 +249,13 @@ export class Converter { } private createNode( - node: TSESTreeToTSNode, - data: TSESTree.OptionalRangeAndLoc, + // The 'parent' property will be added later if specified + node: Omit, 'parent'>, + data: Omit, 'parent'>, ): T { const result = data; if (!result.range) { - result.range = getRange( - // this is completely valid, but TS hates it - node as never, - this.ast, - ); + result.range = getRange(node, this.ast); } if (!result.loc) { result.loc = getLocFor(result.range[0], result.range[1], this.ast); @@ -310,7 +307,7 @@ export class Converter { loc, range: [annotationStartCol, child.end], typeAnnotation: this.convertType(child), - }; + } as TSESTree.TSTypeAnnotation; } /** @@ -389,7 +386,7 @@ export class Converter { params: typeParameters.map(typeParameter => this.convertType(typeParameter), ), - }; + } as TSESTree.TSTypeParameterDeclaration; } /** diff --git a/packages/typescript-estree/src/node-utils.ts b/packages/typescript-estree/src/node-utils.ts index 2b7351b0408..929d63cfcdf 100644 --- a/packages/typescript-estree/src/node-utils.ts +++ b/packages/typescript-estree/src/node-utils.ts @@ -222,7 +222,10 @@ export function canContainDirective( * @param ast the AST object * @returns the range data */ -export function getRange(node: ts.Node, ast: ts.SourceFile): [number, number] { +export function getRange( + node: Pick, + ast: ts.SourceFile, +): [number, number] { return [node.getStart(ast), node.getEnd()]; } @@ -484,9 +487,8 @@ export function getTokenType( // A TypeScript-StringLiteral token with a TypeScript-JsxAttribute or TypeScript-JsxElement parent, // must actually be an ESTree-JSXText token if ( - token.parent && - (token.parent.kind === SyntaxKind.JsxAttribute || - token.parent.kind === SyntaxKind.JsxElement) + token.parent.kind === SyntaxKind.JsxAttribute || + token.parent.kind === SyntaxKind.JsxElement ) { return AST_TOKEN_TYPES.JSXText; } @@ -506,7 +508,7 @@ export function getTokenType( } // Some JSX tokens have to be determined based on their parent - if (token.parent && token.kind === SyntaxKind.Identifier) { + if (token.kind === SyntaxKind.Identifier) { if (isJSXToken(token.parent)) { return AST_TOKEN_TYPES.JSXIdentifier; } diff --git a/packages/utils/src/ts-eslint/Rule.ts b/packages/utils/src/ts-eslint/Rule.ts index f22e71400cf..a8df03d681e 100644 --- a/packages/utils/src/ts-eslint/Rule.ts +++ b/packages/utils/src/ts-eslint/Rule.ts @@ -260,7 +260,9 @@ interface RuleContext< // This isn't the correct signature, but it makes it easier to do custom unions within reusable listeners // never will break someone's code unless they specifically type the function argument -type RuleFunction = (node: T) => void; +type RuleFunction = ( + node: T, +) => void; interface RuleListener { [nodeSelector: string]: RuleFunction | undefined; diff --git a/packages/website/src/components/ASTViewerESTree.tsx b/packages/website/src/components/ASTViewerESTree.tsx index 29b5550cd14..7f7f0cd2bb7 100644 --- a/packages/website/src/components/ASTViewerESTree.tsx +++ b/packages/website/src/components/ASTViewerESTree.tsx @@ -7,7 +7,7 @@ import { createESTreeSerializer } from './ast/serializer/serializerESTree'; import type { ASTViewerBaseProps } from './ast/types'; export interface ASTESTreeViewerProps extends ASTViewerBaseProps { - readonly value: TSESTree.BaseNode; + readonly value: TSESTree.BaseNode | TSESTree.Program; } export default function ASTViewerESTree({