noUnnecessaryConditions
Summary
Section titled “Summary”- Rule available since:
v2.1.4 - Diagnostic Category:
lint/suspicious/noUnnecessaryConditions - This rule isn’t recommended, so you need to enable it.
- This rule doesn’t have a fix.
- The default severity of this rule is warning.
- This rule belongs to the following domains:
- Sources:
- Inspired from
@typescript-eslint/no-unnecessary-condition
- Inspired from
How to configure
Section titled “How to configure”{ "linter": { "rules": { "suspicious": { "noUnnecessaryConditions": "error" } } }}Description
Section titled “Description”Disallow conditions that always evaluate to the same value.
Using type information, this rule reports conditions whose result is
statically known. It covers if/while/for/ternary tests, the ??
and ||/&& operators, optional chaining (?.), comparisons against
null/undefined, and case clauses that can never match the value
passed to switch.
Examples
Section titled “Examples”Invalid
Section titled “Invalid”A non-nullable value never needs an if guard:
function head<T>(items: T[]) { if (items) { return items[0]; }}code-block.ts:2:9 lint/suspicious/noUnnecessaryConditions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
⚠ This condition is always truthy.
1 │ function head<T>(items: T[]) {
> 2 │ if (items) {
│ ^^^^^
3 │ return items[0];
4 │ }
ℹ The value’s type can never be falsy, so this check is redundant.
A literal-union type can never be empty, so the truthiness check is redundant:
function foo(arg: 'bar' | 'baz') { if (arg) {}}code-block.ts:2:9 lint/suspicious/noUnnecessaryConditions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
⚠ This condition is always truthy.
1 │ function foo(arg: ‘bar’ | ‘baz’) {
> 2 │ if (arg) {}
│ ^^^
3 │ }
4 │
ℹ The value’s type can never be falsy, so this check is redundant.
?. and ?? on operands that are guaranteed to be non-nullish:
function bar(arg: string) { return arg?.length;}code-block.ts:2:12 lint/suspicious/noUnnecessaryConditions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
⚠ Unnecessary optional chaining.
1 │ function bar(arg: string) {
> 2 │ return arg?.length;
│ ^^^
3 │ }
4 │
ℹ Replace ?. with ..
1 │ function bar(arg: string) {
> 2 │ return arg?.length;
│ ^^
3 │ }
4 │
ℹ The receiver is guaranteed to be non-nullish.
function withDefault(name: string) { return name ?? "anonymous";}code-block.ts:2:12 lint/suspicious/noUnnecessaryConditions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
⚠ Unnecessary nullish coalescing.
1 │ function withDefault(name: string) {
> 2 │ return name ?? “anonymous”;
│ ^^^^
3 │ }
4 │
ℹ Drop ?? and the fallback expression.
1 │ function withDefault(name: string) {
> 2 │ return name ?? “anonymous”;
│ ^^
3 │ }
4 │
ℹ The left-hand side is guaranteed to be non-nullish, so the fallback is unreachable.
|| and && on always-truthy operands:
interface Config { items: string[] }function f(c: Config) { return c.items || [];}code-block.ts:3:12 lint/suspicious/noUnnecessaryConditions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
⚠ This condition is always truthy.
1 │ interface Config { items: string[] }
2 │ function f(c: Config) {
> 3 │ return c.items || [];
│ ^^^^^^^
4 │ }
5 │
ℹ The value’s type can never be falsy, so this check is redundant.
!expr on a value that is always truthy:
const items = [];if (!items) {}code-block.ts:2:5 lint/suspicious/noUnnecessaryConditions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
⚠ This condition is always falsy.
1 │ const items = [];
> 2 │ if (!items) {}
│ ^^^^^^
3 │
ℹ The value’s type can never be truthy, so this check is redundant.
Comparing a non-nullable value against null or undefined:
function f(x: string) { return x === null;}code-block.ts:2:12 lint/suspicious/noUnnecessaryConditions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
⚠ This comparison always has the same result.
1 │ function f(x: string) {
> 2 │ return x === null;
│ ^^^^^^^^^^
3 │ }
4 │
ℹ The operands’ types make the outcome statically known.
A case whose value can never equal the value passed to switch:
function f(v: 'a' | 'b') { switch (v) { case 'c': return 1; }}code-block.ts:3:14 lint/suspicious/noUnnecessaryConditions ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
⚠ This case is unreachable.
1 │ function f(v: ‘a’ | ‘b’) {
2 │ switch (v) {
> 3 │ case ‘c’: return 1;
│ ^^^
4 │ }
5 │ }
ℹ The value passed to switch can never equal this value.
When the type allows nullish or empty values, the check is meaningful. The rule also does not report bindings that are reassigned to values of different truthiness, since their narrowing cannot be inferred reliably.
function head<T>(items: T[] | null) { if (items) { return items[0]; }}
function bar(arg: string | undefined) { return arg?.length;}
function f(v: 'a' | 'b' | 'c') { switch (v) { case 'a': break; case 'b': break; case 'c': break; }}
let greeting = false;function update() { greeting = "Hello"; }if (greeting) {}Related links
Section titled “Related links”Copyright (c) 2023-present Biome Developers and Contributors.