Skip to content
Advertisement

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

I’m trying to find if there is a non-plugin eslint rule that would allow any of the following:

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

But only error on this:

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}`;

In favour of using ternary assignment like so:

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

// or

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

Does that rule (or a combination of rules) exist for eslint without involving a plug-in?

Advertisement

Answer

With using only base ESLint, you could try the no-restricted-syntax rule. It is not specific but can disallow any syntax you want.

To figure out how you want to configure this rule, check:

  • place your code in a tool that can generate the abstract syntax tree (AST) which will tell you what you want to forbid. The one I used is https://astexplorer.net/
  • the ESLint guide on selectors which outlines how AST selectors can be used and combined. They are very similar to CSS selectors but target programming code.

With these two, here is what I came up with. This is just an example, you might want to adjust the rule further:

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

This will forbid assignments in single-line if statements (and in else). Note that it does not apply for blocks. Allowed

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

Disallowed:

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

For reference, the selector for if statements with a block body that contains an assignment would be IfStatement > BlockStatement > ExpressionStatement > AssignmentExpression

This will only disallow assignments not variable declarations. A construct like const x = 42; falls under VariableDeclaration in AST, so AssignmentExpression is separate and only apply when a variable is already declared.

Try the online ESLint demo with:

/* 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

As I said, this is just to showcase the functionality. It does not encourage you into using conditional statements (the error message just amounts to “don’t use this”) and might also not cover everything you want (e.g., assignment in if which is inside another if). But it is a start.

Still, you might want to look at making a custom plugin that more accurately checks for what you want and reports better errors. The no-restricted-syntax rule is probably too generic for most use cases.

User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement