Skip to content

noUnnecessaryConditions

biome.json
{
"linter": {
"rules": {
"suspicious": {
"noUnnecessaryConditions": "error"
}
}
}
}

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.

A non-nullable value never needs an if guard:

function head<T>(items: T[]) {
if (items) {
return items[0];
}
}

A literal-union type can never be empty, so the truthiness check is redundant:

function foo(arg: 'bar' | 'baz') {
if (arg) {}
}

?. and ?? on operands that are guaranteed to be non-nullish:

function bar(arg: string) {
return arg?.length;
}
function withDefault(name: string) {
return name ?? "anonymous";
}

|| and && on always-truthy operands:

interface Config { items: string[] }
function f(c: Config) {
return c.items || [];
}

!expr on a value that is always truthy:

const items = [];
if (!items) {}

Comparing a non-nullable value against null or undefined:

function f(x: string) {
return x === null;
}

A case whose value can never equal the value passed to switch:

function f(v: 'a' | 'b') {
switch (v) {
case 'c': return 1;
}
}

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) {}