diff --git a/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts b/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts index c4bed147eb88..e6eaf77190f6 100644 --- a/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts +++ b/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts @@ -751,8 +751,13 @@ export default createRule({ if (propType) { return isNullableType(propType); } + const indexInfo = checker.getIndexInfosOfType(type); - return !!checker.getIndexInfoOfType(type, ts.IndexKind.String); + return indexInfo.some( + info => + getTypeName(checker, info.keyType) === 'string' && + 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 7aaed5539e21..8c92e36dd8b0 100644 --- a/packages/eslint-plugin/tests/rules/no-unnecessary-condition.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unnecessary-condition.test.ts @@ -982,6 +982,34 @@ isString('falafel'); `, options: [{ checkTypePredicates: true }], }, + ` +type A = { [name in Lowercase]?: A }; +declare const a: A; +a.a?.a?.a; + `, + ` +interface T { + [name: Lowercase]: { + [name: Lowercase]: { + [name: Lowercase]: { + value: 'value'; + }; + }; + }; + [name: Uppercase]: null | { + [name: Uppercase]: null | { + [name: Uppercase]: null | { + VALUE: 'VALUE'; + }; + }; + }; +} + +declare const t: T; + +t.a.a.a.value; +t.A?.A?.A?.VALUE; + `, ], invalid: [ @@ -2766,5 +2794,111 @@ isString('fa' + 'lafel'); '((string & { __brandA: string }) | (number & { __brandB: string })) & ("foo" | 123)', 'alwaysTruthy', ), + { + code: ` +type A = { + [name in Lowercase]?: { + [name in Lowercase]: { + a: 1; + }; + }; +}; + +declare const a: A; + +a.a?.a?.a; + `, + errors: [ + { + column: 7, + endColumn: 9, + endLine: 12, + line: 12, + messageId: 'neverOptionalChain', + }, + ], + output: ` +type A = { + [name in Lowercase]?: { + [name in Lowercase]: { + a: 1; + }; + }; +}; + +declare const a: A; + +a.a?.a.a; + `, + }, + { + code: ` +interface T { + [name: Lowercase]: { + [name: Lowercase]: { + [name: Lowercase]: { + value: 'value'; + }; + }; + }; + [name: Uppercase]: null | { + [name: Uppercase]: null | { + [name: Uppercase]: null | { + VALUE: 'VALUE'; + }; + }; + }; +} + +declare const t: T; + +t.a?.a?.a?.value; + `, + errors: [ + { + column: 4, + endColumn: 6, + endLine: 21, + line: 21, + messageId: 'neverOptionalChain', + }, + { + column: 7, + endColumn: 9, + endLine: 21, + line: 21, + messageId: 'neverOptionalChain', + }, + { + column: 10, + endColumn: 12, + endLine: 21, + line: 21, + messageId: 'neverOptionalChain', + }, + ], + output: ` +interface T { + [name: Lowercase]: { + [name: Lowercase]: { + [name: Lowercase]: { + value: 'value'; + }; + }; + }; + [name: Uppercase]: null | { + [name: Uppercase]: null | { + [name: Uppercase]: null | { + VALUE: 'VALUE'; + }; + }; + }; +} + +declare const t: T; + +t.a.a.a.value; + `, + }, ], }); 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