How To Guide

Fix 'Expected an Assignment or Function Call' in ESLint

How-to guide for fixing ESLint's no-unused-expressions error with four common causes and code fixes.

{ "slug": "how-to-fix-expected-assignment-or-function-call", "title": "Fix 'Expected an Assignment or Function Call' in ESLint", "description": "Fix ESLint's no-unused-expressions error. Learn the four common causes including arrow function object literals, ternaries, and short-circuits with code fixes.", "type": "how-to", "toolSlugs": ["eslint", "javascript", "react", "prettier"], "keywords": ["eslint no-unused-expressions", "expected an assignment or function call", "arrow function return object", "ternary expression eslint", "short-circuit expression", "javascript eslint error", "react eslint fix", "jsx expression error"], "steps": [ {"name": "Identify the reported line", "text": "Open the file and jump to the line ESLint flagged. The error means that entire statement evaluates a value that is thrown away."}, {"name": "Check for arrow functions returning objects", "text": "Look for arrow functions using braces around an object literal. Wrap the object in parentheses so it is returned, not treated as a block."}, {"name": "Convert side-effect ternaries to if statements", "text": "Replace `cond ? doA() : doB()` used only for its side effects with a real `if/else` block so ESLint recognises the intent."}, {"name": "Ensure short-circuits actually call something", "text": "For `a && b`, confirm `b` is a function call or assignment. If not, invoke it or switch to an `if` statement."}, {"name": "Re-run ESLint to verify", "text": "Run `npx eslint ` and confirm the rule no longer fires. Add a test if the fix changed runtime behaviour."} ], "content": "

Fix ESLint 'Expected an assignment or function call and instead saw an expression'

\n

This warning comes from ESLint's no-unused-expressions rule. It fires when a statement evaluates a value but never uses it, meaning the line probably does nothing at runtime. Below are the four causes that account for almost every real-world hit, each with a minimal reproduction and the corrected code.

\n\n

1. Arrow function returning an object literal without parentheses

\n

This is by far the most common cause, especially in React and Redux code. Concise arrow bodies interpret { ... } as a function body, not an object. Property keys like a: are then parsed as labels, and the value expression is unused.

\n
// Broken: parsed as a block with label 'name', string is unused\nconst mapUser = user => { name: user.name, id: user.id };\n\n// Fixed: parentheses force object-literal parsing\nconst mapUser = user => ({ name: user.name, id: user.id });
\n

The same trap hits Redux selectors and RTK Query transformers:

\n
// Broken\nconst selectVisible = state => { items: state.items.filter(i => i.visible) };\n\n// Fixed\nconst selectVisible = state => ({ items: state.items.filter(i => i.visible) });
\n\n

2. Ternary expression used only for side effects

\n

Ternaries return a value. When you write one at statement level to do two things, the resulting value is discarded and ESLint complains. Use if/else instead.

\n
// Broken\nuser.isAdmin ? grantAccess(user) : denyAccess(user);\n\n// Fixed\nif (user.isAdmin) {\n  grantAccess(user);\n} else {\n  denyAccess(user);\n}
\n

If you really want an expression, assign or return the result:

\n
const result = user.isAdmin ? grantAccess(user) : denyAccess(user);
\n\n

3. Short-circuit expression that never calls anything

\n

The pattern condition && doSomething() is idiomatic, but only when doSomething() is actually invoked. Forgetting the parentheses turns it into a plain value lookup with no effect.

\n
// Broken: reads the property but never calls it\nisReady && onReady;\n\n// Fixed\nisReady && onReady();
\n

The same pattern with optional chaining bites teams migrating older code:

\n
// Broken\nuser?.logout;\n\n// Fixed\nuser?.logout();
\n

If the right side is not a callable, prefer an explicit statement:

\n
if (isReady) status = 'done';
\n\n

4. Forgetting parentheses on a function call

\n

Referencing a function without invoking it evaluates to the function object and then throws it away.

\n
// Broken\nfunction init() {\n  setup;          // reference, not a call\n  render;         // reference, not a call\n}\n\n// Fixed\nfunction init() {\n  setup();\n  render();\n}
\n

The same happens with method calls copied from documentation:

\n
// Broken\nresponse.json;\n\n// Fixed\nconst data = await response.json();
\n\n

Verifying the fix

\n

After changing the line, re-run ESLint against just that file to confirm:

\n
npx eslint src/components/UserCard.jsx
\n

If the rule still fires, the statement almost certainly still evaluates to a discarded value. Read it aloud as \"take this value and throw it away\" — that framing makes the problem obvious.

\n\n

When to disable the rule

\n

Occasionally you have a legitimate expression statement, such as a Chai assertion (expect(x).to.be.true) or a directive prologue. Configure exceptions rather than disabling the rule globally:

\n
// .eslintrc.js\nrules: {\n  'no-unused-expressions': ['error', {\n    allowShortCircuit: true,\n    allowTernary: true,\n    allowTaggedTemplates: true,\n  }],\n}
\n

For Chai specifically, install eslint-plugin-chai-friendly so the rule ignores assertion chains without turning off protection for the rest of your codebase.

" }
eslint no-unused-expressions expected an assignment or function call arrow function return object ternary expression eslint short-circuit expression javascript eslint error react eslint fix jsx expression error

Explore 300+ Free Tools

Utilko has tools for developers, writers, designers, students, and everyday users — all free, all browser-based.