Search code examples
reactjstypescripteslinteslint-config-airbnbtypescript-eslint

ESLint Espected an assignment or function call and instead saw an expression on void function


Issue Description:

I've begun working on a project with and . Issue is, eslint gives me an unexpected error on what seems to be a properly declared function


Code:

import React, { useState } from 'react';

type Props = {
  options: Array<string>
};

const Switch: React.FC<Props> = (props: Props) => {
  const [choice, setChoice] = useState<number>(0);

  // eslint gives error @ following function
  const handleSwitchChange = ():void => {
    choice + 1 >= options.length ? setChoice(0) : setChoice(choice + 1)
  };

  return (
    <div>{options[choice]}</div>
    <button onClick={handleSwitchChange}>Change choice</button>
  );
};

Further details:

Now this works as expected, but despite the fact the function I'm passing to is of declared type void eslint gives me the following error:

Expected an assignment or function call and instead saw an expression.

Now I don't want to just disable the rule, but I don't see anything inherently wrong with the code. Is there any way to write the function properly so es-lint doesn't complain?


ESLint error (extra info)

The specific eslint module which raises the error

 {
    "resource": "<PATH CENSORED>/src/components/forms/Switch.tsx",
    "owner": "eslint",
    "code": "@typescript-eslint/no-unused-expressions",
    "severity": 8,
    "message": "Expected an assignment or function call and instead saw an expression.",
    "source": "eslint",
    "startLineNumber": 12,
    "startColumn": 5,
    "endLineNumber": 12,
    "endColumn": 85
}

Solution

  • When you have an arrow function with curly braces, its body must include at least one statement (as the error message suggests, an assignment or function call, or an if or return statement or something similar):

    const handleSwitchChange = {
      // Statements must go here
    };
    

    You've actually given an expression that (type checking aside) could appear on the right-hand side of an assignment or a function parameter:

    // Syntactically valid, not necessarily meaningful
    const hypothetical = choice + 1 >= options.length ? setChoice(0) : setChoice(choice + 1);
    someFunction(choice + 1 >= options.length ? setChoice(0) : setChoice(choice + 1));
    

    You have a couple of options. Easiest is to change the arrow function to a form that takes an expression by removing the curly braces

    const handleSwitchChange = (): void =>
      choice + 1 >= options.length ? setChoice(0) : setChoice(choice + 1);
    

    There are various ways to refactor this to look more like a statement, like replacing the ternary operator with an if statement, or by moving the function up to the top level.

    // Equally valid with or without curly braces
    // (Curly braces explicitly ignore the return value)
    const handleSwitchChange = (): void => {
      setChoice(choice + 1 >= options.length ? 0 : choice + 1);
    };