是否有 eslint 规则来防止在单行 if 语句中赋值?

Is there an eslint rule to prevent assignment in a single line if statement?

我正在尝试查找是否存在允许以下任何一项的非插件 eslint 规则:

function(x) {
let count = 0;
  if (doIncrement(x)) count++
  else (doDecrement(x)) count--
  if (count >=10) return "over nine";
  else return "keep counting";
}

但唯一的错误是:

let listOfThings = [];
if (treatAsString) listOfThings[0] = myString.trim();
else listOfThings = [...myString.split(',').map(stringPart => stringPart.trim())];


// or

let name = '';
if (hasFirstAndLAstName) name = `${firstName} ${lastName}`;
else name = `${emailAddress}`;

赞成像这样使用三元赋值:

const listOfThings = treatAsString
  ? [myString.trim()]
  : [...myString.split(',').map(stringPart => stringPart.trim())];

// or

let name = hasFirstAndLAstName ? `${firstName} ${lastName}` : emailAddress;

不涉及插件的 eslint 是否存在该规则(或规则组合)?

目前没有非插件的。

事实上,即使像 prefer-ternary 这样的插件规则也不会捕捉到复杂的情况,例如你的失败案例,包括索引字段分配与完全重新分配,我将其归类为 'uber-complex'。

仅使用基础 ESLint,您可以尝试 no-restricted-syntax rule。它不是特定的,但可以禁止您想要的任何语法。

要了解您希望如何配置此规则,请检查:

  • 将你的代码放在一个可以生成抽象语法树 (AST) 的工具中,它会告诉你你想禁止什么。我用的是https://astexplorer.net/
  • the ESLint guide on selectors 概述了 如何使用和组合 AST 选择器。它们与 CSS 选择器非常相似,但目标是编程代码。

有了这两个,这就是我想出的。这只是一个示例,您可能需要进一步调整规则:

no-restricted-syntax: ["error", "IfStatement > ExpressionStatement > AssignmentExpression"]

这将禁止在单行 if 语句(和 else 中)赋值。请注意,它 不适用于块 。 允许

let x;
if (Math.random() > 0.5) {
    x = 4;
} else {
    x = 2;
}

不允许:

let x;
if (Math.random() > 0.5) x = 4;
else x = 2;

作为参考,块体包含赋值的 if 语句的选择器将是 IfStatement > BlockStatement > ExpressionStatement > AssignmentExpression

这只会禁止赋值而不是变量声明。像 const x = 42; 这样的构造在 AST 中属于 VariableDeclaration,因此 AssignmentExpression 是独立的,并且仅在已声明变量时应用。

尝试在线 ESLint 演示:

/* eslint no-restricted-syntax: ["error", "IfStatement > ExpressionStatement > AssignmentExpression"] */

// allowed
function foo(x) {
  let count = 0;
  if (doIncrement(x)) count++
  else if (doDecrement(x)) count--
  if (count >=10) return "over nine";
  else return "keep counting";
}

// allowed
function foo() {
  const listOfThings = treatAsString
    ? [myString.trim()]
    : [...myString.split(',').map(stringPart => stringPart.trim())];
}

// allowed
function foo() {
  let name = hasFirstAndLAstName ? `${firstName} ${lastName}` : emailAddress;
}

// allowed - assignment is not in `if`
function foo() {
  let x = 1;
  x = 2;
}

// allowed - if statement with blocks
function foo() {
  let x;
  if (Math.random() > 0.5) {
    x = 4;
  } else {
     x = 2;
  }
}

// disallowed
function foo() {
  let listOfThings = [];
  if (treatAsString) listOfThings[0] = myString.trim();
  else listOfThings = [...myString.split(',').map(stringPart => stringPart.trim())];
}

// disallowed
function foo() {
  let name = '';
  if (hasFirstAndLAstName) name = `${firstName} ${lastName}`;
  else name = `${emailAddress}`;
}

// disallowed - single line `if` (even though there is no `else`)
function foo() {
  let x = 1;
  if (Math.random() > 0.5)
    x = 2;
}

Direct link to online ESLint demo

正如我所说,这只是为了展示功能。它不鼓励你使用条件语句(错误消息只是“不要使用这个”)并且可能也没有涵盖你想要的一切(例如,在 if 中的赋值在另一个 if).但这是一个开始。

不过,您可能想要制作一个自定义插件,它可以更准确地检查您想要的内容并报告更好的错误。对于大多数用例,no-restricted-syntax 规则可能 通用。