Disallow conditionals where the type is always truthy or always falsy.
💡
Some problems reported by this rule are manually fixable by editor suggestions.
💭
This rule requires type information to run, which comes with performance tradeoffs.
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.
eslint.config.mjs
export default tseslint.config({
rules: {
"@typescript-eslint/no-unnecessary-condition": "error"
}
});
.eslintrc.cjs
module.exports = {
"rules": {
"@typescript-eslint/no-unnecessary-condition": "error"
}
};
Try this rule in the playground ↗
Examplesfunction head<T>(items: T[]) {
if (items) {
return items[0].toUpperCase();
}
}
function foo(arg: 'bar' | 'baz') {
if (arg) {
}
}
function bar<T>(arg: string) {
return arg?.length;
}
[
[1, 2],
[3, 4],
].filter(t => t);
Open in Playground
function head<T>(items: T[]) {
if (items.length) {
return items[0].toUpperCase();
}
}
function foo(arg: string) {
if (arg) {
}
}
function bar(arg?: string | null) {
return arg?.length;
}
[0, 1, 2, 3].filter(t => t);
Open in Playground Options
This rule accepts the following options:
type Options = [
{
allowConstantLoopConditions?:
| 'always'
| 'never'
| 'only-allowed-literals'
| boolean;
allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing?: boolean;
checkTypePredicates?: boolean;
},
];
const defaultOptions: Options = [
{
allowConstantLoopConditions: 'never',
allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing: false,
checkTypePredicates: false,
},
];
allowConstantLoopConditions
Whether to ignore constant loop conditions, such as while (true)
. Default: "never"
.
'never'
Disallow constant conditions in loops. Same as false
.
Example of incorrect code for { allowConstantLoopConditions: 'never' }
:
'always'
Allow constant conditions in loops. Same as true
.
Example of correct code for { allowConstantLoopConditions: 'always' }
:
'only-allowed-literals'
Permit idiomatic constant literal conditions in while
loop conditions.
Specifically, true
, false
, 0
, and 1
are allowed despite always being truthy or falsy, as these are common patterns and are not likely to represent developer errors.
Example of correct code for { allowConstantLoopConditions: 'only-allowed-literals' }
:
Example of incorrect code for { allowConstantLoopConditions: 'only-allowed-literals' }
:
declare const alwaysTrue: true;
while (alwaysTrue) {
}
const thisIsTrue = true;
while (thisIsTrue) {
}
Open in Playground checkTypePredicates
Whether to check the asserted argument of a type predicate function for unnecessary conditions Default: false
.
Example of additional incorrect code with { checkTypePredicates: true }
:
function assert(condition: unknown): asserts condition {
if (!condition) {
throw new Error('Condition is falsy');
}
}
assert(false);
const neverNull = {};
assert(neverNull);
function isString(value: unknown): value is string {
return typeof value === 'string';
}
declare const s: 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);
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
Whether to not error when running with a tsconfig that has strictNullChecks turned. Default: false
.
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.
This rule is powered by TypeScript types, therefore, if the types do not match match the runtime behavior, the rule may report inaccurately. This can happen in several commonplace scenarios.
Possibly-undefined indexed accessBy default, TypeScript optimistically assumes that indexed access will always return a value. This means that cases like the following will be erroneously flagged as unnecessary conditions:
const array: string[] = [];
const firstElement = array[0];
if (firstElement != null) {
}
const record: Record<string, string> = {};
const someValue = record.someKey;
if (someValue != null) {
}
Open in Playground
To get pessimistic, but correct, types for these cases, you can use TypeScript's noUncheckedIndexedAccess
compiler option, though this is often unwieldy in real-world usage. Another workaround is to use array.at(0)
(which is always possibly-undefined) to indicate array access that may be out-of-bounds. Otherwise, a disable comment will often make sense for these kinds of cases.
The following code will be erroneously flagged as unnecessary, even though the condition is modified within the function call.
let condition = false;
const f = () => {
condition = Math.random() > 0.5;
};
f();
if (condition) {
}
Open in Playground
This occurs due to limitations of TypeScript's type narrowing. See microsoft/TypeScript#9998 for details. We recommend using a type assertion in these cases, like so:
let condition = false as boolean;
const f = () => {
condition = Math.random() > 0.5;
};
f();
if (condition) {
}
Open in Playground 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.
no-unnecessary-condition
is essentially a stronger version of no-constant-condition
, but requires type information.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 degradations after enabling type checked rules.
ResourcesRetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4