diff --git a/packages/eslint-plugin/src/rules/prefer-optional-chain-utils/analyzeChain.ts b/packages/eslint-plugin/src/rules/prefer-optional-chain-utils/analyzeChain.ts index 84c1ca6e9593..a2b11134e540 100644 --- a/packages/eslint-plugin/src/rules/prefer-optional-chain-utils/analyzeChain.ts +++ b/packages/eslint-plugin/src/rules/prefer-optional-chain-utils/analyzeChain.ts @@ -10,7 +10,7 @@ import type { } from '@typescript-eslint/utils/ts-eslint'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; -import { isFalsyType, unionConstituents } from 'ts-api-utils'; +import { unionConstituents } from 'ts-api-utils'; import * as ts from 'typescript'; import type { LastChainOperand, ValidOperand } from './gatherLogicalOperands'; @@ -48,40 +48,6 @@ function includesType( return false; } -function isAlwaysTruthyOperand( - comparedName: TSESTree.Node, - nullishComparisonType: NullishComparisonType, - parserServices: ParserServicesWithTypeInformation, -): boolean { - const ANY_UNKNOWN_FLAGS = ts.TypeFlags.Any | ts.TypeFlags.Unknown; - const comparedNameType = parserServices.getTypeAtLocation(comparedName); - - if (isTypeFlagSet(comparedNameType, ANY_UNKNOWN_FLAGS)) { - return false; - } - switch (nullishComparisonType) { - case NullishComparisonType.Boolean: - case NullishComparisonType.NotBoolean: { - const types = unionConstituents(comparedNameType); - return types.every(type => !isFalsyType(type)); - } - case NullishComparisonType.NotStrictEqualUndefined: - case NullishComparisonType.NotStrictEqualNull: - case NullishComparisonType.StrictEqualNull: - case NullishComparisonType.StrictEqualUndefined: - return !isTypeFlagSet( - comparedNameType, - ts.TypeFlags.Null | ts.TypeFlags.Undefined, - ); - case NullishComparisonType.NotEqualNullOrUndefined: - case NullishComparisonType.EqualNullOrUndefined: - return !isTypeFlagSet( - comparedNameType, - ts.TypeFlags.Null | ts.TypeFlags.Undefined, - ); - } -} - function isValidAndLastChainOperand( ComparisonValueType: TSESTree.Node, comparisonType: ComparisonType, @@ -710,20 +676,6 @@ export function analyzeChain( } break; } - case NullishComparisonType.StrictEqualNull: - case NullishComparisonType.NotStrictEqualNull: { - if ( - comparisonResult === NodeComparisonResult.Subset && - isAlwaysTruthyOperand( - lastOperand.comparedName, - lastOperand.comparisonType, - parserServices, - ) - ) { - lastChain = operand; - } - break; - } } } maybeReportThenReset(); @@ -768,16 +720,11 @@ export function analyzeChain( : isValidOrLastChainOperand; if ( comparisonResult === NodeComparisonResult.Subset && - (isAlwaysTruthyOperand( - lastOperand.comparedName, - lastOperand.comparisonType, + isValidLastChainOperand( + lastChainOperand.comparisonValue, + lastChainOperand.comparisonType, parserServices, - ) || - isValidLastChainOperand( - lastChainOperand.comparisonValue, - lastChainOperand.comparisonType, - parserServices, - )) + ) ) { lastChain = lastChainOperand; } diff --git a/packages/eslint-plugin/tests/rules/prefer-optional-chain/prefer-optional-chain.test.ts b/packages/eslint-plugin/tests/rules/prefer-optional-chain/prefer-optional-chain.test.ts index a990d70b60bb..52c59b479b68 100644 --- a/packages/eslint-plugin/tests/rules/prefer-optional-chain/prefer-optional-chain.test.ts +++ b/packages/eslint-plugin/tests/rules/prefer-optional-chain/prefer-optional-chain.test.ts @@ -861,215 +861,6 @@ describe('chain ending with comparison', () => { errors: [{ messageId: 'preferOptionalChain', suggestions: null }], output: `foo?.bar != null;`, }, - { - code: ` - declare const foo: { bar: number }; - foo && foo.bar == x; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar == x; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo && foo.bar == null; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar == null; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo && foo.bar == undefined; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar == undefined; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo && foo.bar === x; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar === x; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo && foo.bar === undefined; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar === undefined; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo && foo.bar !== 0; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar !== 0; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo && foo.bar !== 1; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar !== 1; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo && foo.bar !== '123'; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar !== '123'; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo && foo.bar !== {}; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar !== {}; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo && foo.bar !== false; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar !== false; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo && foo.bar !== true; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar !== true; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo && foo.bar !== null; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar !== null; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo && foo.bar !== x; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar !== x; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo && foo.bar != 0; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar != 0; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo && foo.bar != 1; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar != 1; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo && foo.bar != '123'; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar != '123'; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo && foo.bar != {}; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar != {}; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo && foo.bar != false; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar != false; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo && foo.bar != true; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar != true; - `, - }, { code: ` declare const foo: { bar: number }; @@ -1081,226 +872,6 @@ describe('chain ending with comparison', () => { foo?.bar != null; `, }, - { - code: ` - declare const foo: { bar: number }; - foo && foo.bar != x; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar != x; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo != null && foo.bar == x; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar == x; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo != null && foo.bar == null; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar == null; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo != null && foo.bar == undefined; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar == undefined; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo != null && foo.bar === x; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar === x; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo != null && foo.bar === undefined; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar === undefined; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo != null && foo.bar !== 0; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar !== 0; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo != null && foo.bar !== 1; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar !== 1; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo != null && foo.bar !== '123'; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar !== '123'; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo != null && foo.bar !== {}; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar !== {}; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo != null && foo.bar !== false; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar !== false; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo != null && foo.bar !== true; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar !== true; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo != null && foo.bar !== null; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar !== null; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo != null && foo.bar !== x; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar !== x; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo != null && foo.bar != 0; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar != 0; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo != null && foo.bar != 1; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar != 1; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo != null && foo.bar != '123'; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar != '123'; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo != null && foo.bar != {}; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar != {}; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo != null && foo.bar != false; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar != false; - `, - }, - { - code: ` - declare const foo: { bar: number }; - foo != null && foo.bar != true; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar != true; - `, - }, { code: ` declare const foo: { bar: number }; @@ -1312,39 +883,6 @@ describe('chain ending with comparison', () => { foo?.bar != null; `, }, - { - code: ` - declare const foo: { bar: number }; - foo != null && foo.bar != x; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar != x; - `, - }, - { - code: ` - declare const foo: { bar: number } | 1; - foo && foo.bar == x; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number } | 1; - foo?.bar == x; - `, - }, - { - code: ` - declare const foo: { bar: number } | 0; - foo != null && foo.bar == x; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number } | 0; - foo?.bar == x; - `, - }, { code: '!foo || foo.bar != 0;', errors: [{ messageId: 'preferOptionalChain', suggestions: null }], @@ -1505,17 +1043,6 @@ describe('chain ending with comparison', () => { errors: [{ messageId: 'preferOptionalChain', suggestions: null }], output: `foo?.bar !== null;`, }, - { - code: ` - declare const foo: { bar: number }; - !foo || foo.bar == x; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar == x; - `, - }, { code: ` declare const foo: { bar: number }; @@ -1538,17 +1065,6 @@ describe('chain ending with comparison', () => { foo?.bar == undefined; `, }, - { - code: ` - declare const foo: { bar: number }; - !foo || foo.bar === x; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar === x; - `, - }, { code: ` declare const foo: { bar: number }; @@ -1637,17 +1153,6 @@ describe('chain ending with comparison', () => { foo?.bar !== null; `, }, - { - code: ` - declare const foo: { bar: number }; - !foo || foo.bar !== x; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar !== x; - `, - }, { code: ` declare const foo: { bar: number }; @@ -1714,40 +1219,6 @@ describe('chain ending with comparison', () => { foo?.bar != true; `, }, - { - code: ` - declare const foo: { bar: number }; - !foo || foo.bar != null; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar != null; - `, - }, - { - code: ` - declare const foo: { bar: number }; - !foo || foo.bar != x; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar != x; - `, - }, - - { - code: ` - declare const foo: { bar: number }; - foo == null || foo.bar == x; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar == x; - `, - }, { code: ` declare const foo: { bar: number }; @@ -1770,17 +1241,6 @@ describe('chain ending with comparison', () => { foo?.bar == undefined; `, }, - { - code: ` - declare const foo: { bar: number }; - foo == null || foo.bar === x; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar === x; - `, - }, { code: ` declare const foo: { bar: number }; @@ -1869,17 +1329,6 @@ describe('chain ending with comparison', () => { foo?.bar !== null; `, }, - { - code: ` - declare const foo: { bar: number }; - foo == null || foo.bar !== x; - `, - errors: [{ messageId: 'preferOptionalChain', suggestions: null }], - output: ` - declare const foo: { bar: number }; - foo?.bar !== x; - `, - }, // yoda case { code: "foo != null && null != foo.bar && '123' == foo.bar.baz;", @@ -1898,10 +1347,10 @@ describe('chain ending with comparison', () => { }, ], valid: [ - 'foo && foo.bar == x;', + 'foo && foo.bar == undeclaredVar;', 'foo && foo.bar == null;', 'foo && foo.bar == undefined;', - 'foo && foo.bar === x;', + 'foo && foo.bar === undeclaredVar;', 'foo && foo.bar === undefined;', 'foo && foo.bar !== 0;', 'foo && foo.bar !== 1;', @@ -1910,18 +1359,18 @@ describe('chain ending with comparison', () => { 'foo && foo.bar !== false;', 'foo && foo.bar !== true;', 'foo && foo.bar !== null;', - 'foo && foo.bar !== x;', + 'foo && foo.bar !== undeclaredVar;', 'foo && foo.bar != 0;', 'foo && foo.bar != 1;', "foo && foo.bar != '123';", 'foo && foo.bar != {};', 'foo && foo.bar != false;', 'foo && foo.bar != true;', - 'foo && foo.bar != x;', - 'foo != null && foo.bar == x;', + 'foo && foo.bar != undeclaredVar;', + 'foo != null && foo.bar == undeclaredVar;', 'foo != null && foo.bar == null;', 'foo != null && foo.bar == undefined;', - 'foo != null && foo.bar === x;', + 'foo != null && foo.bar === undeclaredVar;', 'foo != null && foo.bar === undefined;', 'foo != null && foo.bar !== 0;', 'foo != null && foo.bar !== 1;', @@ -1930,17 +1379,185 @@ describe('chain ending with comparison', () => { 'foo != null && foo.bar !== false;', 'foo != null && foo.bar !== true;', 'foo != null && foo.bar !== null;', - 'foo != null && foo.bar !== x;', + 'foo != null && foo.bar !== undeclaredVar;', 'foo != null && foo.bar != 0;', 'foo != null && foo.bar != 1;', "foo != null && foo.bar != '123';", 'foo != null && foo.bar != {};', 'foo != null && foo.bar != false;', 'foo != null && foo.bar != true;', - 'foo != null && foo.bar != x;', + 'foo != null && foo.bar != undeclaredVar;', + ` + declare const foo: { bar: number }; + foo && foo.bar == undeclaredVar; + `, + ` + declare const foo: { bar: number }; + foo && foo.bar == null; + `, + ` + declare const foo: { bar: number }; + foo && foo.bar == undefined; + `, + ` + declare const foo: { bar: number }; + foo && foo.bar === undeclaredVar; + `, + ` + declare const foo: { bar: number }; + foo && foo.bar === undefined; + `, + ` + declare const foo: { bar: number }; + foo && foo.bar !== 0; + `, + ` + declare const foo: { bar: number }; + foo && foo.bar !== 1; + `, + ` + declare const foo: { bar: number }; + foo && foo.bar !== '123'; + `, + ` + declare const foo: { bar: number }; + foo && foo.bar !== {}; + `, + ` + declare const foo: { bar: number }; + foo && foo.bar !== false; + `, + ` + declare const foo: { bar: number }; + foo && foo.bar !== true; + `, + ` + declare const foo: { bar: number }; + foo && foo.bar !== null; + `, + ` + declare const foo: { bar: number }; + foo && foo.bar !== undeclaredVar; + `, + ` + declare const foo: { bar: number }; + foo && foo.bar != 0; + `, + ` + declare const foo: { bar: number }; + foo && foo.bar != 1; + `, + ` + declare const foo: { bar: number }; + foo && foo.bar != '123'; + `, + ` + declare const foo: { bar: number }; + foo && foo.bar != {}; + `, + ` + declare const foo: { bar: number }; + foo && foo.bar != false; + `, + ` + declare const foo: { bar: number }; + foo && foo.bar != true; + `, + ` + declare const foo: { bar: number }; + foo && foo.bar != undeclaredVar; + `, + ` + declare const foo: { bar: number }; + foo != null && foo.bar == undeclaredVar; + `, + ` + declare const foo: { bar: number }; + foo != null && foo.bar == null; + `, + ` + declare const foo: { bar: number }; + foo != null && foo.bar == undefined; + `, + ` + declare const foo: { bar: number }; + foo != null && foo.bar === undeclaredVar; + `, + ` + declare const foo: { bar: number }; + foo != null && foo.bar === undefined; + `, + ` + declare const foo: { bar: number }; + foo != null && foo.bar !== 0; + `, + ` + declare const foo: { bar: number }; + foo != null && foo.bar !== 1; + `, + ` + declare const foo: { bar: number }; + foo != null && foo.bar !== '123'; + `, + ` + declare const foo: { bar: number }; + foo != null && foo.bar !== {}; + `, + ` + declare const foo: { bar: number }; + foo != null && foo.bar !== false; + `, + ` + declare const foo: { bar: number }; + foo != null && foo.bar !== true; + `, + ` + declare const foo: { bar: number }; + foo != null && foo.bar !== null; + `, + ` + declare const foo: { bar: number }; + foo != null && foo.bar !== undeclaredVar; + `, + ` + declare const foo: { bar: number }; + foo != null && foo.bar != 0; + `, + ` + declare const foo: { bar: number }; + foo != null && foo.bar != 1; + `, + ` + declare const foo: { bar: number }; + foo != null && foo.bar != '123'; + `, + ` + declare const foo: { bar: number }; + foo != null && foo.bar != {}; + `, + ` + declare const foo: { bar: number }; + foo != null && foo.bar != false; + `, + ` + declare const foo: { bar: number }; + foo != null && foo.bar != true; + `, + ` + declare const foo: { bar: number }; + foo != null && foo.bar != undeclaredVar; + `, + ` + declare const foo: { bar: number } | 1; + foo && foo.bar == undeclaredVar; + `, + ` + declare const foo: { bar: number } | 0; + foo != null && foo.bar == undeclaredVar; + `, ` declare const foo: { bar: number } | null; - foo && foo.bar == x; + foo && foo.bar == undeclaredVar; `, ` declare const foo: { bar: number } | null; @@ -1952,7 +1569,7 @@ describe('chain ending with comparison', () => { `, ` declare const foo: { bar: number } | null; - foo && foo.bar === x; + foo && foo.bar === undeclaredVar; `, ` declare const foo: { bar: number } | null; @@ -1988,11 +1605,11 @@ describe('chain ending with comparison', () => { `, ` declare const foo: { bar: number } | null; - foo && foo.bar !== x; + foo && foo.bar !== undeclaredVar; `, ` declare const foo: { bar: number } | null; - foo != null && foo.bar == x; + foo != null && foo.bar == undeclaredVar; `, ` declare const foo: { bar: number } | null; @@ -2004,7 +1621,7 @@ describe('chain ending with comparison', () => { `, ` declare const foo: { bar: number } | null; - foo != null && foo.bar === x; + foo != null && foo.bar === undeclaredVar; `, ` declare const foo: { bar: number } | null; @@ -2040,7 +1657,7 @@ describe('chain ending with comparison', () => { `, ` declare const foo: { bar: number } | null; - foo != null && foo.bar !== x; + foo != null && foo.bar !== undeclaredVar; `, ` declare const foo: { bar: number } | null; @@ -2108,6 +1725,26 @@ describe('chain ending with comparison', () => { declare const foo: { bar: number } | undefined; foo !== undefined && foo !== undefined && foo.bar != 1; `, + ` + declare const foo: { bar: number }; + !foo || foo.bar == undeclaredVar; + `, + ` + declare const foo: { bar: number }; + !foo || foo.bar === undeclaredVar; + `, + ` + declare const foo: { bar: number }; + !foo || foo.bar !== undeclaredVar; + `, + ` + declare const foo: { bar: number }; + !foo || foo.bar != null; + `, + ` + declare const foo: { bar: number }; + !foo || foo.bar != undeclaredVar; + `, '!foo && foo.bar == 0;', '!foo && foo.bar == 1;', "!foo && foo.bar == '123';", @@ -2141,22 +1778,22 @@ describe('chain ending with comparison', () => { 'foo == null && foo.bar != null;', 'foo == null && foo.bar != undefined;', ` - declare const x: false | { a: string }; - x && x.a == x; + declare const foo: false | { a: string }; + foo && foo.a == undeclaredVar; `, ` - declare const x: '' | { a: string }; - x && x.a == x; + declare const foo: '' | { a: string }; + foo && foo.a == undeclaredVar; `, ` - declare const x: 0 | { a: string }; - x && x.a == x; + declare const foo: 0 | { a: string }; + foo && foo.a == undeclaredVar; `, ` - declare const x: 0n | { a: string }; - x && x.a; + declare const foo: 0n | { a: string }; + foo && foo.a; `, - '!foo || foo.bar != x;', + '!foo || foo.bar != undeclaredVar;', '!foo || foo.bar != null;', '!foo || foo.bar != undefined;', '!foo || foo.bar === 0;', @@ -2166,17 +1803,29 @@ describe('chain ending with comparison', () => { '!foo || foo.bar === false;', '!foo || foo.bar === true;', '!foo || foo.bar === null;', - '!foo || foo.bar === x;', + '!foo || foo.bar === undeclaredVar;', '!foo || foo.bar == 0;', '!foo || foo.bar == 1;', "!foo || foo.bar == '123';", '!foo || foo.bar == {};', '!foo || foo.bar == false;', '!foo || foo.bar == true;', - '!foo || foo.bar == x;', - '!foo || foo.bar !== x;', + '!foo || foo.bar == undeclaredVar;', + '!foo || foo.bar !== undeclaredVar;', '!foo || foo.bar !== undefined;', - 'foo == null || foo.bar != x;', + ` + declare const foo: { bar: number }; + foo == null || foo.bar == undeclaredVar; + `, + ` + declare const foo: { bar: number }; + foo == null || foo.bar === undeclaredVar; + `, + ` + declare const foo: { bar: number }; + foo == null || foo.bar !== undeclaredVar; + `, + 'foo == null || foo.bar != undeclaredVar;', 'foo == null || foo.bar != null;', 'foo == null || foo.bar != undefined;', 'foo == null || foo.bar === 0;', @@ -2186,15 +1835,15 @@ describe('chain ending with comparison', () => { 'foo == null || foo.bar === false;', 'foo == null || foo.bar === true;', 'foo == null || foo.bar === null;', - 'foo == null || foo.bar === x;', + 'foo == null || foo.bar === undeclaredVar;', 'foo == null || foo.bar == 0;', 'foo == null || foo.bar == 1;', "foo == null || foo.bar == '123';", 'foo == null || foo.bar == {};', 'foo == null || foo.bar == false;', 'foo == null || foo.bar == true;', - 'foo == null || foo.bar == x;', - 'foo == null || foo.bar !== x;', + 'foo == null || foo.bar == undeclaredVar;', + 'foo == null || foo.bar !== undeclaredVar;', 'foo == null || foo.bar !== undefined;', 'foo || foo.bar != 0;', 'foo || foo.bar != 1;', @@ -2228,6 +1877,14 @@ describe('chain ending with comparison', () => { 'foo != null || foo.bar !== false;', 'foo != null || foo.bar !== true;', 'foo != null || foo.bar !== null;', + ` + declare const record: Record; + record['key'] && record['key'].kind !== '1'; + `, + ` + declare const array: { b?: string }[]; + !array[1] || array[1].b === 'foo'; + `, ], }); }); @@ -3489,7 +3146,6 @@ describe('base cases', () => { mutateCode: c => c.replaceAll('&&', '!== null &&'), mutateOutput: identity, operator: '&&', - skipIds: [20, 26], }), // but if the type is just `| null` - then it covers the cases and is // a valid conversion @@ -3501,45 +3157,6 @@ describe('base cases', () => { operator: '&&', useSuggestionFixer: true, }), - { - code: ` - declare const foo: { - bar: () => - | { baz: { buzz: (() => number) | null | undefined } | null | undefined } - | null - | undefined; - }; - foo.bar !== null && - foo.bar() !== null && - foo.bar().baz !== null && - foo.bar().baz.buzz !== null && - foo.bar().baz.buzz(); - `, - errors: [{ messageId: 'preferOptionalChain' }], - output: ` - declare const foo: { - bar: () => - | { baz: { buzz: (() => number) | null | undefined } | null | undefined } - | null - | undefined; - }; - foo.bar?.() !== null && - foo.bar().baz !== null && - foo.bar().baz.buzz !== null && - foo.bar().baz.buzz(); - `, - }, - { - code: ` - declare const foo: { bar: () => { baz: number } | null | undefined }; - foo.bar !== null && foo.bar?.() !== null && foo.bar?.().baz; - `, - errors: [{ messageId: 'preferOptionalChain' }], - output: ` - declare const foo: { bar: () => { baz: number } | null | undefined }; - foo.bar?.() !== null && foo.bar?.().baz; - `, - }, ], }); }); @@ -3654,7 +3271,6 @@ describe('base cases', () => { mutateCode: c => c.replaceAll('||', '=== null ||'), mutateOutput: identity, operator: '||', - skipIds: [20, 26], }), // but if the type is just `| null` - then it covers the cases and is // a valid conversion @@ -3671,45 +3287,6 @@ describe('base cases', () => { operator: '||', useSuggestionFixer: true, }), - { - code: ` - declare const foo: { - bar: () => - | { baz: { buzz: (() => number) | null | undefined } | null | undefined } - | null - | undefined; - }; - foo.bar === null || - foo.bar() === null || - foo.bar().baz === null || - foo.bar().baz.buzz === null || - foo.bar().baz.buzz(); - `, - errors: [{ messageId: 'preferOptionalChain' }], - output: ` - declare const foo: { - bar: () => - | { baz: { buzz: (() => number) | null | undefined } | null | undefined } - | null - | undefined; - }; - foo.bar?.() === null || - foo.bar().baz === null || - foo.bar().baz.buzz === null || - foo.bar().baz.buzz(); - `, - }, - { - code: ` - declare const foo: { bar: () => { baz: number } | null | undefined }; - foo.bar === null || foo.bar?.() === null || foo.bar?.().baz; - `, - errors: [{ messageId: 'preferOptionalChain' }], - output: ` - declare const foo: { bar: () => { baz: number } | null | undefined }; - foo.bar?.() === null || foo.bar?.().baz; - `, - }, ], }); });