strict-boolean-expressions
Disallow certain types in boolean expressions.
Forbids usage of non-boolean types in expressions where a boolean is expected.
boolean
and never
types are always allowed.
Additional types which are considered safe in a boolean context can be configured via options.
The following nodes are considered boolean expressions and their type is checked:
- Argument to the logical negation operator (
!arg
). - The condition in a conditional expression (
cond ? x : y
). - Conditions for
if
,for
,while
, anddo-while
statements. - Operands of logical binary operators (
lhs || rhs
andlhs && rhs
).- Right-hand side operand is ignored when it's not a descendant of another boolean expression. This is to allow usage of boolean operators for their short-circuiting behavior.
Attributes
- Included in configs
- ✅ Recommended
- 🔒 Strict
- Fixable
- 🔧 Automated Fixer
- 💡 Suggestion Fixer
- 💭 Requires type information
Examples
Examples of code for this rule:
- ❌ Incorrect
- ✅ Correct
// nullable numbers are considered unsafe by default
let num: number | undefined = 0;
if (num) {
console.log('num is defined');
}
// nullable strings are considered unsafe by default
let str: string | null = null;
if (!str) {
console.log('str is empty');
}
// nullable booleans are considered unsafe by default
function foo(bool?: boolean) {
if (bool) {
bar();
}
}
// `any`, unconstrained generics and unions of more than one primitive type are disallowed
const foo = <T>(arg: T) => (arg ? 1 : 0);
// always-truthy and always-falsy types are disallowed
let obj = {};
while (obj) {
obj = getObj();
}
// Using logical operator short-circuiting is allowed
const Component = () => {
const entry = map.get('foo') || {};
return entry && <p>Name: {entry.name}</p>;
};
// nullable values should be checked explicitly against null or undefined
let num: number | undefined = 0;
if (num != null) {
console.log('num is defined');
}
let str: string | null = null;
if (str != null && !str) {
console.log('str is empty');
}
function foo(bool?: boolean) {
if (bool ?? false) {
bar();
}
}
// `any` types should be cast to boolean explicitly
const foo = (arg: any) => (Boolean(arg) ? 1 : 0);
module.exports = {
"rules": {
"@typescript-eslint/strict-boolean-expressions": "warn"
}
};
Options
This rule accepts an options object with the following properties:
interface Options {
allowString?: boolean;
allowNumber?: boolean;
allowNullableObject?: boolean;
allowNullableBoolean?: boolean;
allowNullableString?: boolean;
allowNullableNumber?: boolean;
allowAny?: boolean;
allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing?: boolean;
}
const defaultOptions: Options = [
{
allowString: true,
allowNumber: true,
allowNullableObject: true,
allowNullableBoolean: false,
allowNullableString: false,
allowNullableNumber: false,
allowAny: false,
allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing: false,
},
];
allowString
Allows string
in a boolean context.
This is safe because strings have only one falsy value (""
).
Set this to false
if you prefer the explicit str != ""
or str.length > 0
style.
allowNumber
Allows number
in a boolean context.
This is safe because numbers have only two falsy values (0
and NaN
).
Set this to false
if you prefer the explicit num != 0
and !Number.isNaN(num)
style.
allowNullableObject
Allows object | function | symbol | null | undefined
in a boolean context.
This is safe because objects, functions and symbols don't have falsy values.
Set this to false
if you prefer the explicit obj != null
style.
allowNullableBoolean
Allows boolean | null | undefined
in a boolean context.
This is unsafe because nullable booleans can be either false
or nullish.
Set this to false
if you want to enforce explicit bool ?? false
or bool ?? true
style.
Set this to true
if you don't mind implicitly treating false the same as a nullish value.
allowNullableString
Allows string | null | undefined
in a boolean context.
This is unsafe because nullable strings can be either an empty string or nullish.
Set this to true
if you don't mind implicitly treating an empty string the same as a nullish value.
allowNullableNumber
Allows number | null | undefined
in a boolean context.
This is unsafe because nullable numbers can be either a falsy number or nullish.
Set this to true
if you don't mind implicitly treating zero or NaN the same as a nullish value.
allowAny
Allows any
in a boolean context.
This is unsafe for obvious reasons.
Set this to true
at your own risk.
allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing
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 a lot less useful.
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.
Fixes and Suggestions
This rule provides following fixes and suggestions for particular types in boolean context:
boolean
- Always allowed - no fix needed.string
- (whenallowString
isfalse
) - Provides following suggestions:- Change condition to check string's length (
str
→str.length > 0
) - Change condition to check for empty string (
str
→str !== ""
) - Explicitly cast value to a boolean (
str
→Boolean(str)
)
- Change condition to check string's length (
number
- (whenallowNumber
isfalse
):- For
array.length
- Provides autofix:- Change condition to check for 0 (
array.length
→array.length > 0
)
- Change condition to check for 0 (
- For other number values - Provides following suggestions:
- Change condition to check for 0 (
num
→num !== 0
) - Change condition to check for NaN (
num
→!Number.isNaN(num)
) - Explicitly cast value to a boolean (
num
→Boolean(num)
)
- Change condition to check for 0 (
- For
object | null | undefined
- (whenallowNullableObject
isfalse
) - Provides autofix:- Change condition to check for null/undefined (
maybeObj
→maybeObj != null
)
- Change condition to check for null/undefined (
boolean | null | undefined
- Provides following suggestions:- Explicitly treat nullish value the same as false (
maybeBool
→maybeBool ?? false
) - Change condition to check for true/false (
maybeBool
→maybeBool === true
)
- Explicitly treat nullish value the same as false (
string | null | undefined
- Provides following suggestions:- Change condition to check for null/undefined (
maybeStr
→maybeStr != null
) - Explicitly treat nullish value the same as an empty string (
maybeStr
→maybeStr ?? ""
) - Explicitly cast value to a boolean (
maybeStr
→Boolean(maybeStr)
)
- Change condition to check for null/undefined (
number | null | undefined
- Provides following suggestions:- Change condition to check for null/undefined (
maybeNum
→maybeNum != null
) - Explicitly treat nullish value the same as 0 (
maybeNum
→maybeNum ?? 0
) - Explicitly cast value to a boolean (
maybeNum
→Boolean(maybeNum)
)
- Change condition to check for null/undefined (
any
andunknown
- Provides following suggestions:- Explicitly cast value to a boolean (
value
→Boolean(value)
)
- Explicitly cast value to a boolean (
Related To
- no-unnecessary-condition - Similar rule which reports always-truthy and always-falsy values in conditions