diff --git a/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts b/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts index c9660416a81b..19e292b0db8c 100644 --- a/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts +++ b/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts @@ -273,6 +273,10 @@ export default createRule({ compilerOptions, 'strictNullChecks', ); + const isNoUncheckedIndexedAccess = tsutils.isCompilerOptionEnabled( + compilerOptions, + 'noUncheckedIndexedAccess', + ); if ( !isStrictNullChecks && @@ -756,11 +760,15 @@ export default createRule({ } const indexInfo = checker.getIndexInfosOfType(type); - return indexInfo.some( - info => - getTypeName(checker, info.keyType) === 'string' && - isNullableType(info.type), - ); + return indexInfo.some(info => { + const isStringTypeName = + getTypeName(checker, info.keyType) === 'string'; + + return ( + isStringTypeName && + (isNoUncheckedIndexedAccess || isNullableType(info.type)) + ); + }); }); return !isOwnNullable && isNullableType(prevType); } diff --git a/packages/eslint-plugin/tests/rules/no-unnecessary-condition.test.ts b/packages/eslint-plugin/tests/rules/no-unnecessary-condition.test.ts index de69b94afac3..f179b7c1d8fb 100644 --- a/packages/eslint-plugin/tests/rules/no-unnecessary-condition.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unnecessary-condition.test.ts @@ -27,6 +27,12 @@ const optionsWithExactOptionalPropertyTypes = { tsconfigRootDir: rootPath, }; +const optionsWithNoUncheckedIndexedAccess = { + project: './tsconfig.noUncheckedIndexedAccess.json', + projectService: false, + tsconfigRootDir: getFixturesRootDir(), +}; + const necessaryConditionTest = (condition: string): string => ` declare const b1: ${condition}; declare const b2: boolean; @@ -591,11 +597,7 @@ const key = '1' as BrandedKey; foo?.[key]?.trim(); `, languageOptions: { - parserOptions: { - project: './tsconfig.noUncheckedIndexedAccess.json', - projectService: false, - tsconfigRootDir: getFixturesRootDir(), - }, + parserOptions: optionsWithNoUncheckedIndexedAccess, }, }, { @@ -649,11 +651,7 @@ function Foo(outer: Outer, key: Foo): number | undefined { } `, languageOptions: { - parserOptions: { - project: './tsconfig.noUncheckedIndexedAccess.json', - projectService: false, - tsconfigRootDir: getFixturesRootDir(), - }, + parserOptions: optionsWithNoUncheckedIndexedAccess, }, }, { @@ -666,11 +664,51 @@ declare const key: Key; foo?.[key]?.trim(); `, languageOptions: { - parserOptions: { - project: './tsconfig.noUncheckedIndexedAccess.json', - projectService: false, - tsconfigRootDir: getFixturesRootDir(), - }, + parserOptions: optionsWithNoUncheckedIndexedAccess, + }, + }, + { + code: ` +type Foo = { + key?: Record; +}; +declare const foo: Foo; +foo.key?.someKey?.key; + `, + languageOptions: { + parserOptions: optionsWithNoUncheckedIndexedAccess, + }, + }, + { + code: ` +type Foo = { + key?: { + [key: string]: () => void; + }; +}; +declare const foo: Foo; +foo.key?.value?.(); + `, + languageOptions: { + parserOptions: optionsWithNoUncheckedIndexedAccess, + }, + }, + { + code: ` +type A = { + [name in Lowercase]?: { + [name in Lowercase]: { + a: 1; + }; + }; +}; + +declare const a: A; + +a.a?.a?.a; + `, + languageOptions: { + parserOptions: optionsWithNoUncheckedIndexedAccess, }, }, ` pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy