@@ -261,12 +261,6 @@ export default createRule<Options, MessageId>({
261261 }
262262
263263 function checkNodeForNullish ( node : TSESTree . Expression ) : void {
264- // Since typescript array index signature types don't represent the
265- // possibility of out-of-bounds access, if we're indexing into an array
266- // just skip the check, to avoid false positives
267- if ( isArrayIndexExpression ( node ) ) {
268- return ;
269- }
270264 const type = getNodeType ( node ) ;
271265 // Conditional is always necessary if it involves `any` or `unknown`
272266 if ( isTypeAnyType ( type ) || isTypeUnknownType ( type ) ) {
@@ -277,7 +271,19 @@ export default createRule<Options, MessageId>({
277271 if ( isTypeFlagSet ( type , ts . TypeFlags . Never ) ) {
278272 messageId = 'never' ;
279273 } else if ( ! isPossiblyNullish ( type ) ) {
280- messageId = 'neverNullish' ;
274+ // Since typescript array index signature types don't represent the
275+ // possibility of out-of-bounds access, if we're indexing into an array
276+ // just skip the check, to avoid false positives
277+ if (
278+ ! isArrayIndexExpression ( node ) &&
279+ ! (
280+ node . type === AST_NODE_TYPES . ChainExpression &&
281+ node . expression . type !== AST_NODE_TYPES . TSNonNullExpression &&
282+ optionChainContainsOptionArrayIndex ( node . expression )
283+ )
284+ ) {
285+ messageId = 'neverNullish' ;
286+ }
281287 } else if ( isAlwaysNullish ( type ) ) {
282288 messageId = 'alwaysNullish' ;
283289 }
@@ -477,19 +483,19 @@ export default createRule<Options, MessageId>({
477483 // ?.x // type is {y: "z"}
478484 // ?.y // This access is considered "unnecessary" according to the types
479485 // ```
480- function optionChainContainsArrayIndex (
486+ function optionChainContainsOptionArrayIndex (
481487 node : TSESTree . MemberExpression | TSESTree . CallExpression ,
482488 ) : boolean {
483489 const lhsNode =
484490 node . type === AST_NODE_TYPES . CallExpression ? node . callee : node . object ;
485- if ( isArrayIndexExpression ( lhsNode ) ) {
491+ if ( node . optional && isArrayIndexExpression ( lhsNode ) ) {
486492 return true ;
487493 }
488494 if (
489495 lhsNode . type === AST_NODE_TYPES . MemberExpression ||
490496 lhsNode . type === AST_NODE_TYPES . CallExpression
491497 ) {
492- return optionChainContainsArrayIndex ( lhsNode ) ;
498+ return optionChainContainsOptionArrayIndex ( lhsNode ) ;
493499 }
494500 return false ;
495501 }
@@ -584,7 +590,7 @@ export default createRule<Options, MessageId>({
584590 // Since typescript array index signature types don't represent the
585591 // possibility of out-of-bounds access, if we're indexing into an array
586592 // just skip the check, to avoid false positives
587- if ( optionChainContainsArrayIndex ( node ) ) {
593+ if ( optionChainContainsOptionArrayIndex ( node ) ) {
588594 return ;
589595 }
590596
0 commit comments