Skip to main content

no-unnecessary-condition

Disallow conditionals where the type is always truthy or always falsy.

🔧

Some problems reported by this rule are automatically fixable by the --fix ESLint command line option.

💭

This rule requires type information to run.

Any expression being used as a condition must be able to evaluate as truthy or falsy in order to be considered "necessary". Conversely, any expression that always evaluates to truthy or always evaluates to falsy, as determined by the type of the expression, is considered unnecessary and will be flagged by this rule.

The following expressions are checked:

  • Arguments to the &&, || and ?: (ternary) operators
  • Conditions for if, for, while, and do-while statements
  • cases in switch statements
  • Base values of optional chain expressions
.eslintrc.cjs
module.exports = {
"rules": {
"@typescript-eslint/no-unnecessary-condition": "error"
}
};

Try this rule in the playground ↗

Examples

function head<T>(items: T[]) {
// items can never be nullable, so this is unnecessary
if (items) {
return items[0].toUpperCase();
}
}

function foo(arg: 'bar' | 'baz') {
// arg is never nullable or empty string, so this is unnecessary
if (arg) {
}
}

function bar<T>(arg: string) {
// arg can never be nullish, so ?. is unnecessary
return arg?.length;
}

// Checks array predicate return types, where possible
[
[1, 2],
[3, 4],
].filter(t => t); // number[] is always truthy
Open in Playground

Options

This rule accepts the following options:

type Options = [
{
/** Whether to ignore constant loop conditions, such as `while (true)`. */
allowConstantLoopConditions?: boolean;
/** Whether to not error when running with a tsconfig that has strictNullChecks turned. */
allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing?: boolean;
/** Whether to check the asserted argument of a type predicate function for unnecessary conditions */
checkTypePredicates?: boolean;
},
];

const defaultOptions: Options = [
{
allowConstantLoopConditions: false,
allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing: false,
checkTypePredicates: false,
},
];

allowConstantLoopConditions

Example of correct code for { allowConstantLoopConditions: true }:

while (true) {}
for (; true; ) {}
do {} while (true);
Open in Playground

checkTypePredicates

Example of additional incorrect code with { checkTypePredicates: true }:

function assert(condition: unknown): asserts condition {
if (!condition) {
throw new Error('Condition is falsy');
}
}

assert(false); // Unnecessary; condition is always falsy.

const neverNull = {};
assert(neverNull); // Unnecessary; condition is always truthy.

function isString(value: unknown): value is string {
return typeof value === 'string';
}

declare const s: string;

// Unnecessary; s is always a string.
if (isString(s)) {
}

function assertIsString(value: unknown): asserts value is string {
if (!isString(value)) {
throw new Error('Value is not a string');
}
}

assertIsString(s); // Unnecessary; s is always a string.
Open in Playground

Whether this option makes sense for your project may vary. Some projects may intentionally use type predicates to ensure that runtime values do indeed match the types according to TypeScript, especially in test code. Often, it makes sense to use eslint-disable comments in these cases, with a comment indicating why the condition should be checked at runtime, despite appearing unnecessary. However, in some contexts, it may be more appropriate to keep this option disabled entirely.

allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing

Deprecated

This option will be removed in the next major version of typescript-eslint.

If this is set to false, then the rule will error on every file whose tsconfig.json does not have the strictNullChecks compiler option (or strict) set to true.

Without strictNullChecks, TypeScript essentially erases undefined and null from the types. This means when this rule inspects the types from a variable, it will not be able to tell that the variable might be null or undefined, which essentially makes this rule useless.

You should be using strictNullChecks to ensure complete type-safety in your codebase.

If for some reason you cannot turn on strictNullChecks, but still want to use this rule - you can use this option to allow it - but know that the behavior of this rule is undefined with the compiler option turned off. We will not accept bug reports if you are using this option.

When Not To Use It

If your project is not accurately typed, such as if it's in the process of being converted to TypeScript or is susceptible to trade-offs in control flow analysis, it may be difficult to enable this rule for particularly non-type-safe areas of code. You might consider using ESLint disable comments for those specific situations instead of completely disabling this rule.

This rule has a known edge case of triggering on conditions that were modified within function calls (as side effects). It is due to limitations of TypeScript's type narrowing. See #9998 for details. We recommend using a type assertion in those cases.

let condition = false as boolean;

const f = () => (condition = true);
f();

if (condition) {
}
  • ESLint: no-constant-condition - no-unnecessary-condition is essentially a stronger version of no-constant-condition, but requires type information.
  • strict-boolean-expressions - a more opinionated version of no-unnecessary-condition. strict-boolean-expressions enforces a specific code style, while no-unnecessary-condition is about correctness.

Type checked lint rules are more powerful than traditional lint rules, but also require configuring type checked linting.

See Troubleshooting > Linting with Type Information > Performance if you experience performance degredations after enabling type checked rules.

Resources