Skip to content

Commit 1ae1d01

Browse files
fix(eslint-plugin): [no-unnecessary-condition] handle comparison of any, unknown and loose comparisons with nullish values (typescript-eslint#2123)
1 parent 9ee399b commit 1ae1d01

File tree

2 files changed

+69
-10
lines changed

2 files changed

+69
-10
lines changed

packages/eslint-plugin/src/rules/no-unnecessary-condition.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import {
55
} from '@typescript-eslint/experimental-utils';
66
import * as ts from 'typescript';
77
import {
8-
isTypeFlagSet,
98
unionTypeParts,
109
isFalsyType,
1110
isBooleanLiteralType,
@@ -14,6 +13,7 @@ import {
1413
isStrictCompilerOptionEnabled,
1514
} from 'tsutils';
1615
import {
16+
isTypeFlagSet,
1717
createRule,
1818
getParserServices,
1919
getConstrainedTypeAtLocation,
@@ -23,9 +23,6 @@ import {
2323
isMemberOrOptionalMemberExpression,
2424
} from '../util';
2525

26-
const typeContainsFlag = (type: ts.Type, flag: ts.TypeFlags): boolean => {
27-
return unionTypeParts(type).some(t => isTypeFlagSet(t, flag));
28-
};
2926
// Truthiness utilities
3027
// #region
3128
const isTruthyLiteral = (type: ts.Type): boolean =>
@@ -268,13 +265,20 @@ export default createRule<Options, MessageId>({
268265
if (isStrictCompilerOptionEnabled(compilerOptions, 'strictNullChecks')) {
269266
const UNDEFINED = ts.TypeFlags.Undefined;
270267
const NULL = ts.TypeFlags.Null;
268+
269+
const NULLISH =
270+
node.operator === '==' || node.operator === '!='
271+
? NULL | UNDEFINED
272+
: NULL;
273+
271274
if (
272275
(leftType.flags === UNDEFINED &&
273-
!typeContainsFlag(rightType, UNDEFINED)) ||
276+
!isTypeFlagSet(rightType, UNDEFINED, true)) ||
274277
(rightType.flags === UNDEFINED &&
275-
!typeContainsFlag(leftType, UNDEFINED)) ||
276-
(leftType.flags === NULL && !typeContainsFlag(rightType, NULL)) ||
277-
(rightType.flags === NULL && !typeContainsFlag(leftType, NULL))
278+
!isTypeFlagSet(leftType, UNDEFINED, true)) ||
279+
(leftType.flags === NULL &&
280+
!isTypeFlagSet(rightType, NULLISH, true)) ||
281+
(rightType.flags === NULL && !isTypeFlagSet(leftType, NULLISH, true))
278282
) {
279283
context.report({ node, messageId: 'noOverlapBooleanExpression' });
280284
return;

packages/eslint-plugin/tests/rules/no-unnecessary-condition.test.ts

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,68 @@ function test<T>(t: T | []) {
100100
// Boolean expressions
101101
`
102102
function test(a: string) {
103-
return a === 'a';
103+
const t1 = a === 'a';
104+
const t2 = 'a' === a;
104105
}
105106
`,
106107
`
107108
function test(a?: string) {
108109
const t1 = a === undefined;
109-
const t3 = undefined === a;
110+
const t2 = undefined === a;
111+
const t1 = a !== undefined;
112+
const t2 = undefined !== a;
113+
}
114+
`,
115+
`
116+
function test(a: null | string) {
117+
const t1 = a === null;
118+
const t2 = null === a;
119+
const t1 = a !== null;
120+
const t2 = null !== a;
121+
}
122+
`,
123+
`
124+
function test(a?: null | string) {
125+
const t1 = a == null;
126+
const t2 = null == a;
127+
const t3 = a != null;
128+
const t4 = null != a;
129+
const t5 = a == undefined;
130+
const t6 = undefined == a;
131+
const t7 = a != undefined;
132+
const t8 = undefined != a;
133+
}
134+
`,
135+
`
136+
function test(a?: string) {
137+
const t1 = a == null;
138+
const t2 = null == a;
139+
const t3 = a != null;
140+
const t4 = null != a;
141+
}
142+
`,
143+
`
144+
function test(a?: null | string) {
145+
const t1 = a == null;
146+
const t2 = null == a;
147+
const t3 = a != null;
148+
const t4 = null != a;
149+
}
150+
`,
151+
`
152+
function test(a: any) {
153+
const t1 = a == null;
154+
const t2 = null == a;
155+
const t3 = a != null;
156+
const t4 = null != a;
157+
}
158+
`,
159+
`
160+
function test(a: unknown) {
161+
const t1 = a == null;
162+
const t2 = null == a;
163+
const t3 = a != null;
164+
const t4 = null != a;
110165
}
111166
`,
112167

0 commit comments

Comments
 (0)
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