Skip to content

Commit

Permalink
fix(eslint-plugin): [no-unnecessary-condition] handle comparison of a…
Browse files Browse the repository at this point in the history
…ny, unknown and loose comparisons with nullish values (#2123)
  • Loading branch information
avocadowastaken committed May 30, 2020
1 parent 9ee399b commit 1ae1d01
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 10 deletions.
20 changes: 12 additions & 8 deletions packages/eslint-plugin/src/rules/no-unnecessary-condition.ts
Expand Up @@ -5,7 +5,6 @@ import {
} from '@typescript-eslint/experimental-utils';
import * as ts from 'typescript';
import {
isTypeFlagSet,
unionTypeParts,
isFalsyType,
isBooleanLiteralType,
Expand All @@ -14,6 +13,7 @@ import {
isStrictCompilerOptionEnabled,
} from 'tsutils';
import {
isTypeFlagSet,
createRule,
getParserServices,
getConstrainedTypeAtLocation,
Expand All @@ -23,9 +23,6 @@ import {
isMemberOrOptionalMemberExpression,
} from '../util';

const typeContainsFlag = (type: ts.Type, flag: ts.TypeFlags): boolean => {
return unionTypeParts(type).some(t => isTypeFlagSet(t, flag));
};
// Truthiness utilities
// #region
const isTruthyLiteral = (type: ts.Type): boolean =>
Expand Down Expand Up @@ -268,13 +265,20 @@ export default createRule<Options, MessageId>({
if (isStrictCompilerOptionEnabled(compilerOptions, 'strictNullChecks')) {
const UNDEFINED = ts.TypeFlags.Undefined;
const NULL = ts.TypeFlags.Null;

const NULLISH =
node.operator === '==' || node.operator === '!='
? NULL | UNDEFINED
: NULL;

if (
(leftType.flags === UNDEFINED &&
!typeContainsFlag(rightType, UNDEFINED)) ||
!isTypeFlagSet(rightType, UNDEFINED, true)) ||
(rightType.flags === UNDEFINED &&
!typeContainsFlag(leftType, UNDEFINED)) ||
(leftType.flags === NULL && !typeContainsFlag(rightType, NULL)) ||
(rightType.flags === NULL && !typeContainsFlag(leftType, NULL))
!isTypeFlagSet(leftType, UNDEFINED, true)) ||
(leftType.flags === NULL &&
!isTypeFlagSet(rightType, NULLISH, true)) ||
(rightType.flags === NULL && !isTypeFlagSet(leftType, NULLISH, true))
) {
context.report({ node, messageId: 'noOverlapBooleanExpression' });
return;
Expand Down
Expand Up @@ -100,13 +100,68 @@ function test<T>(t: T | []) {
// Boolean expressions
`
function test(a: string) {
return a === 'a';
const t1 = a === 'a';
const t2 = 'a' === a;
}
`,
`
function test(a?: string) {
const t1 = a === undefined;
const t3 = undefined === a;
const t2 = undefined === a;
const t1 = a !== undefined;
const t2 = undefined !== a;
}
`,
`
function test(a: null | string) {
const t1 = a === null;
const t2 = null === a;
const t1 = a !== null;
const t2 = null !== a;
}
`,
`
function test(a?: null | string) {
const t1 = a == null;
const t2 = null == a;
const t3 = a != null;
const t4 = null != a;
const t5 = a == undefined;
const t6 = undefined == a;
const t7 = a != undefined;
const t8 = undefined != a;
}
`,
`
function test(a?: string) {
const t1 = a == null;
const t2 = null == a;
const t3 = a != null;
const t4 = null != a;
}
`,
`
function test(a?: null | string) {
const t1 = a == null;
const t2 = null == a;
const t3 = a != null;
const t4 = null != a;
}
`,
`
function test(a: any) {
const t1 = a == null;
const t2 = null == a;
const t3 = a != null;
const t4 = null != a;
}
`,
`
function test(a: unknown) {
const t1 = a == null;
const t2 = null == a;
const t3 = a != null;
const t4 = null != a;
}
`,

Expand Down

0 comments on commit 1ae1d01

Please sign in to comment.