Skip to content

Commit

Permalink
feat(eslint-plugin): [strict-boolean-expressions] Add allowNullable o…
Browse files Browse the repository at this point in the history
…ption (#794)
  • Loading branch information
phaux authored and JamesHenry committed Sep 12, 2019
1 parent 5715482 commit c713ca4
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 3 deletions.
Expand Up @@ -56,6 +56,7 @@ while (typeof str !== 'undefined') {

Options may be provided as an object with:

- `allowNullable` to allow `undefined` and `null` in addition to `boolean` as a type of all boolean expressions. (`false` by default).
- `ignoreRhs` to skip the check on the right hand side of expressions like `a && b` or `a || b` - allows these operators to be used for their short-circuiting behavior. (`false` by default).

## Related To
Expand Down
38 changes: 35 additions & 3 deletions packages/eslint-plugin/src/rules/strict-boolean-expressions.ts
Expand Up @@ -16,6 +16,7 @@ type ExpressionWithTest =
type Options = [
{
ignoreRhs?: boolean;
allowNullable?: boolean;
},
];

Expand All @@ -36,6 +37,9 @@ export default util.createRule<Options, 'strictBooleanExpression'>({
ignoreRhs: {
type: 'boolean',
},
allowNullable: {
type: 'boolean',
},
},
additionalProperties: false,
},
Expand All @@ -47,9 +51,10 @@ export default util.createRule<Options, 'strictBooleanExpression'>({
defaultOptions: [
{
ignoreRhs: false,
allowNullable: false,
},
],
create(context, [{ ignoreRhs }]) {
create(context, [options]) {
const service = util.getParserServices(context);
const checker = service.program.getTypeChecker();

Expand All @@ -61,7 +66,34 @@ export default util.createRule<Options, 'strictBooleanExpression'>({
node,
);
const type = util.getConstrainedTypeAtLocation(checker, tsNode);
return tsutils.isTypeFlagSet(type, ts.TypeFlags.BooleanLike);

if (tsutils.isTypeFlagSet(type, ts.TypeFlags.BooleanLike)) {
return true;
}

// Check variants of union
if (tsutils.isTypeFlagSet(type, ts.TypeFlags.Union)) {
let hasBoolean = false;
for (const ty of (type as ts.UnionType).types) {
if (tsutils.isTypeFlagSet(ty, ts.TypeFlags.BooleanLike)) {
hasBoolean = true;
continue;
}
if (options.allowNullable) {
if (tsutils.isTypeFlagSet(ty, ts.TypeFlags.Null)) {
continue;
}
if (tsutils.isTypeFlagSet(ty, ts.TypeFlags.Undefined)) {
continue;
}
}
// Union variant is something else
return false;
}
return hasBoolean;
}

return false;
}

/**
Expand All @@ -88,7 +120,7 @@ export default util.createRule<Options, 'strictBooleanExpression'>({
): void {
if (
!isBooleanType(node.left) ||
(!ignoreRhs && !isBooleanType(node.right))
(!options.ignoreRhs && !isBooleanType(node.right))
) {
reportNode(node);
}
Expand Down
Expand Up @@ -165,6 +165,15 @@ const boolOrObj = bool || obj;
const boolAndObj = bool && obj;
`,
},
{
options: [{ allowNullable: true }],
code: `
const f1 = (x?: boolean) => x ? 1 : 0;
const f2 = (x: boolean | null) => x ? 1 : 0;
const f3 = (x?: true | null) => x ? 1 : 0;
const f4 = (x?: false) => x ? 1 : 0;
`,
},
],

invalid: [
Expand Down Expand Up @@ -933,5 +942,24 @@ const objOrBool = obj || bool;
const objAndBool = obj && bool;
`,
},
{
options: [{ allowNullable: true }],
errors: [
{
messageId: 'strictBooleanExpression',
line: 2,
column: 44,
},
{
messageId: 'strictBooleanExpression',
line: 3,
column: 35,
},
],
code: `
const f = (x: null | undefined) => x ? 1 : 0;
const f = (x?: number) => x ? 1 : 0;
`,
},
],
});

0 comments on commit c713ca4

Please sign in to comment.