Tslint: 对于非布尔上下文中使用的逻辑运算符,不应触发严格布尔表达式

创建于 2017-10-04  ·  18评论  ·  资料来源: palantir/tslint

错误报告

  • __TSLint 版本__:5.7
  • __打字稿版本__:2.5.3
  • __通过__运行TSLint:CLI

正在整理 TypeScript 代码

// code snippet
function valueOrDefault(a?: string) {
  return a || "the default";
}

使用tslint.json配置:

{
  "defaultSeverity": "error",
  "extends": [
      "tslint:all"
  ]
}

实际行为

获取 2 个错误的报告:
strict-boolean-expressions This type is not allowed in the operand for the '||' operator because it could be undefined. Only booleans are allowed.
strict-boolean-expressions This type is not allowed in the operand for the '||' operator because it is always truthy. Only booleans are allowed.

预期行为

没有报告错误。 我正在使用逻辑||运算符为参数提供默认值(我知道我可以使用函数参数默认声明,该代码段只是为了说明一般问题)。 任何地方都没有boolean起作用:表达式的输入或输出都没有。

Fixed Bug

最有用的评论

在我看来, strict-boolean-expressions应该只检查&&||的左操作数。 这些运算符(本质上)是三元组的糖: a && b等于a ? b : aa || b等于a ? a : b 。 当你从这些方面考虑它时,忽略 RHS 很有意义,它会使短路运算符的行为与三元的行为一致。

然后,如果整个事情都在 if/for/while 中,则strict-boolean-conditions可以发挥作用并检查整体表达式。 我认为这将涵盖所有有用的情况,我将能够重新启用此规则。

对我来说,将此标记为问题的代码是这个记录在案的常见React 模式

function Foo(props: { showToggle: boolean }) {
  return <div>{props.showToggle && <Toggle />}</div>;
}
ERROR: 2:36 strict-boolean-expressions This type is not allowed in the operand for the '&&' operator because it is always truthy. Allowed types are boolean, null-union, undefined-union, string, or number.

@ajafff他的代码没有为我传递

export function valueOrDefault(a?: string) {
  return a || "the default";
}
"strict-boolean-expressions": [true, "allow-null-union", "allow-undefined-union", "allow-string", "allow-number", "allow-mix"]
ERROR: 2:15 strict-boolean-expressions This type is not allowed in the operand for the '||' operator because it is always truthy. Allowed types are boolean, null-union, undefined-union, string, or number.

该表达式的意图是 LHS 的条件,所以我忽略 RHS 的建议也可以解决他的问题。

所有18条评论

想法? 祈祷? 关于从哪里/如何开始的建议?

@marcind你能举例说明它应该如何与改变规则不同吗?

抱歉,我最初提交的哪个部分不清楚?

我想我的观点是这条规则应该只在“布尔上下文”中运行,我可以想到两种情况:

  1. ifwhilefor
  2. 分配给类型为boolean的变量。

当我尝试提供默认值或短路评估时,该规则不应运行

  1. const a: string = potentiallyUndefinedString || "the default";
  2. const a: string | undefined = potentiallyUndefinedObject && potentiallyUndefinedObject.getString()

@marcind如果您使用"allow-undefined-union"选项,您上一篇文章中的示例将起作用。

您请求的另一部分应该是一个名为strict-boolean-conditions的单独规则,它只检查ifforwhiledo ... while和条件表达式( x ? y : z )。
我可以想象它只会检查整个条件的类型,而不是它的组成部分:

function foo(a: boolean, b?: boolean) {
    if (b || a) {} // passes, result is always boolean
    if (b && a) {} // fails, result is boolean | undefined
    if (a || b) {} // fails, result is boolean | undefined
    if (a || !!b) {} // passes
}

也许这可以是现有规则的一个选项,而不是新规则......

在我看来, strict-boolean-expressions应该只检查&&||的左操作数。 这些运算符(本质上)是三元组的糖: a && b等于a ? b : aa || b等于a ? a : b 。 当你从这些方面考虑它时,忽略 RHS 很有意义,它会使短路运算符的行为与三元的行为一致。

然后,如果整个事情都在 if/for/while 中,则strict-boolean-conditions可以发挥作用并检查整体表达式。 我认为这将涵盖所有有用的情况,我将能够重新启用此规则。

对我来说,将此标记为问题的代码是这个记录在案的常见React 模式

function Foo(props: { showToggle: boolean }) {
  return <div>{props.showToggle && <Toggle />}</div>;
}
ERROR: 2:36 strict-boolean-expressions This type is not allowed in the operand for the '&&' operator because it is always truthy. Allowed types are boolean, null-union, undefined-union, string, or number.

@ajafff他的代码没有为我传递

export function valueOrDefault(a?: string) {
  return a || "the default";
}
"strict-boolean-expressions": [true, "allow-null-union", "allow-undefined-union", "allow-string", "allow-number", "allow-mix"]
ERROR: 2:15 strict-boolean-expressions This type is not allowed in the operand for the '||' operator because it is always truthy. Allowed types are boolean, null-union, undefined-union, string, or number.

该表达式的意图是 LHS 的条件,所以我忽略 RHS 的建议也可以解决他的问题。

我同意检查&&||的 RHS 是一个错误。


我也倾向于放松检查的LHS &&||和操作数! 。 这些只应检查表达式是否始终为真或始终为假。
只剩下ifforwhiledo ... while条件和严格检查的条件表达式,只允许布尔值(或其他任何配置)。 想法@adidahiya?

目前,使用可用的配置选项启用此规则需要数天的时间来使用我们的代码库。 :(

我启用了它,希望它能防止numbernullundefined隐式转换为boolean 。 例如:

if (!!array.length) { /* ... */ }


md5-d563d6246c0e981c16f8a2b3d7f53974





md5-430ec08bab82330fa4e519419e9ad014




However I find the following uses acceptable:



md5-70351fc6fdb328ee060919d6974e2cf4



```tsx


md5-036fd2ddd516eac8e1379cdcb9ac2b9a


我认为这与@marcind 的建议一致

我也倾向于放宽对 &&、|| 的 LHS 的检查和!

@ajafff这会使if (!!array.length)if (!possiblyNull)合法化吗?

@ajafff @adidahiya这里

无耻地宣传我自己的项目:
自从我在本期的最后一个活动中,我创建了自己的linterhttps :

它包含一个规则no-useless-predicate ,这可能是您正在寻找的。 它是 TSLint 的strict-type-predicatesstrict-boolean-expressions ,但有一些主要区别:

与 TSLint 的strict-type-predicates它也可以在没有--strictNullChecks并且可以正确处理类型参数和空对象类型。 (对于订阅此问题的人来说可能不太有趣)
与 TSLint 的strict-boolean-expressions的主要区别在于,它不需要所有内容都是布尔值(它不检测隐式强制转换)。 它只要求每个条件都可能为真和假。

一些例子:

if (0) {} // error, always falsy
if (1) {} // error, always truthy
declare let array: string[];
if (array.length) {} // no error
if (!array.length) {} // no error
if (!!array.length) {} // no error
if (array.length === undefined) {} // error, condition is always false
if (!!false) {} // 2 errors, because of the double negation of an always falsy value

declare let someString: string;
return someString || 'some default string'; // no error, because 'someString' might be falsy

declare const foo: 'bar' | 'baz';
return foo || 'bas'; // error, 'foo' is always truthy

declare let optionalFunction: (() => void) | undefined;
optionalFunction && optionalFunction(); // no error

我想从我的实际代码中加入以下用例:

export interface ILoggingRule {
    readonly isFinal?: boolean;
    readonly loggerNamePattern?: string;
    readonly maxLogLevel?: LogLevel;
    readonly minLogLevel?: LogLevel;
    readonly target: Target;
}

// ...

/**
 * Creates an instance of LoggingRule.
 * <strong i="6">@param</strong> options Configuration options of the logging rule.
 */
public constructor(options: ILoggingRule) {
    // tslint:disable:strict-boolean-expressions
    this.isFinal = options.isFinal || false;
    this.loggerNamePattern = options.loggerNamePattern || "*";
    this.maxLogLevel = options.maxLogLevel || LogLevel.Fatal;
    this.minLogLevel = options.minLogLevel || LogLevel.Trace;
    this.target = options.target;
    // tslint:enable:strict-boolean-expressions
}

如您所见,如果 LHS 碰巧未定义,我将使用||来表示默认值。 有什么简洁的方法可以让tslint理解这确实符合strict-boolean-expressions吗? 否则我将被迫使用那些禁用/启用命令。 (令人惊讶的是,这只是启用类型检查的问题,而不是 VSCode。)

这种用法在 JavaScript 中是标准的,非常常见和方便,绝对不会触发此规则失败。

恕我直言,不应检查&&||的 RHS,以允许短路。 这应该是默认行为(或者至少应该有一个像allow-any-rhs这样的选项)。 目前,我不能使用strict-boolean-expressions ,因为我们的代码库中有很多短路。

检查 LHS 应该保持原样恕我直言,因为使用stringnumber作为 LHS 可能很危险,请参阅此示例:

function foo(x: string | number | null) {
  return x || defaultValue;
}

这是危险的,因为许多开发人员将无法理解不仅null而且0""会导致defaultValue返回。

我不得不处理我项目中的主要错误,因为开发人员没有考虑到""0也是假的。 防止这种代码,是我strict-boolean-expressions主要用例。

修复在https://github.com/palantir/tslint/pull/4159只需要合作者的审查。

糟糕,只是想澄清一下我的一个例子很糟糕:

const x = possiblyUndefined || 5;

这不应该起作用,因为possiblyUndefined可能是0 ,这可能是一个逻辑错误。 看起来@dobesv的 PR 可以在这里工作。

包含数组是 ES7 的一个特性。
你需要改变你的 ts 配置才能使用 ES7 或 ESNEXT 🦄

问候,🚀

@rimiti嗨,我不明白你指的是什么,你确定你在正确的线程中发布了该评论吗?

@dobesv哦,你说得对;)

由 #4159 修复,将在下一个版本中可用

此页面是否有帮助?
0 / 5 - 0 等级