Skip to content

fix(eslint-plugin): [no-unnecessary-condition] better handling for unary negation #2382

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Aug 24, 2020
32 changes: 32 additions & 0 deletions packages/eslint-plugin/src/rules/no-unnecessary-condition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,14 @@ export default createRule<Options, MessageId>({
* if the type of the node is always true or always false, it's not necessary.
*/
function checkNode(node: TSESTree.Expression): void {
// Check if the node is Unary Negation expression and handle it
if (
node.type === AST_NODE_TYPES.UnaryExpression &&
node.operator === '!'
) {
return checkIfUnaryNegationExpressionIsNecessaryConditional(node);
}

// Since typescript array index signature types don't represent the
// possibility of out-of-bounds access, if we're indexing into an array
// just skip the check, to avoid false positives
Expand Down Expand Up @@ -213,6 +221,30 @@ export default createRule<Options, MessageId>({
}
}

/**
* If it is Unary Negation Expression, check the argument for alwaysTruthy / alwaysFalsy
*/
function checkIfUnaryNegationExpressionIsNecessaryConditional(
node: TSESTree.UnaryExpression,
): void {
if (isArrayIndexExpression(node.argument)) {
return;
}
const type = getNodeType(node.argument);
const messageId = isTypeFlagSet(type, ts.TypeFlags.Never)
? 'never'
: isPossiblyTruthy(type)
? 'alwaysFalsy'
: isPossiblyFalsy(type)
? 'alwaysTruthy'
: undefined;

if (messageId) {
context.report({ node, messageId });
}
return;
}

function checkNodeForNullish(node: TSESTree.Expression): void {
// Since typescript array index signature types don't represent the
// possibility of out-of-bounds access, if we're indexing into an array
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,26 @@ declare const key: Key;

foo?.[key]?.trim();
`,
// https://github.com/typescript-eslint/typescript-eslint/issues/2384
`
let latencies: number[][] = [];

function recordData(): void {
if (!latencies[0]) latencies[0] = [];
latencies[0].push(4);
}

recordData();
`,
`
let latencies: number[][] = [];

function recordData(): void {
if (latencies[0]) latencies[0] = [];
latencies[0].push(4);
}

recordData();
`,
`
function test(testVal?: boolean) {
if (testVal ?? true) {
Expand All @@ -458,6 +477,34 @@ function test(testVal?: boolean) {
// Ensure that it's checking in all the right places
{
code: `
const a = null;
if (!a) {
}
`,
errors: [ruleError(3, 5, 'alwaysTruthy')],
},
{
code: `
const a = true;
if (!a) {
}
`,
errors: [ruleError(3, 5, 'alwaysFalsy')],
},
{
code: `
function sayHi(): void {
console.log('Hi!');
}

let speech: never = sayHi();
if (!speech) {
}
`,
errors: [ruleError(7, 5, 'never')],
},
{
code: `
const b1 = true;
declare const b2: boolean;
const t1 = b1 && b2;
Expand Down