DEV Community

John Au-Yeung
John Au-Yeung

Posted on

The Best ESLint Rules for Clean and Consistent JavaScript Code

ESLint has become a crucial part of modern JavaScript development. It helps maintain code quality, consistency, and readability by enforcing specific rules.

The tool acts like a virtual pair of eyes that examines your code for patterns that may lead to errors or suboptimal practices. With thousands of possible rules available, developers often struggle to choose the most beneficial ones.

In this article we explore some of the best ESLint rules that strike a balance between rigor and flexibility—without overwhelming you.

no-unused-vars

One of the first and most helpful rules to consider is no-unused-vars.

This rule prevents the declaration of variables that are never used. While it may seem harmless to leave a variable lying around, it can signal unfinished logic or unnecessary clutter in your codebase.

It also leads to cognitive overhead for other developers trying to understand why a variable exists.

eqeqeq

Another critical rule is eqeqeq, which enforces the use of strict equality operators (=== and !==) instead of their loose counterparts (== and !=).

Loose equality can lead to unexpected type coercions, which often cause bugs that are hard to trace.

By enforcing strict equality, your code becomes more predictable and less prone to subtle errors.

no-console

The no-console rule is often debated. In production code, it makes sense to disallow console.log() statements because they clutter the output and can leak sensitive information.

In development environments, this rule can be relaxed, but it’s still wise to flag them so they don’t end up in final builds unnoticed.

no-magic-numbers

One particularly helpful rule for readability is no-magic-numbers.

Magic numbers are numeric literals that appear in your code without explanation, such as if (score > 42).

This rule encourages the use of named constants, which make your code self-documenting and easier to update later. Instead of 42, defining a constant like const PASSING_SCORE = 42 instantly makes your intent clearer.

indent

Consistency in formatting can make or break the maintainability of a codebase.

The indent rule enforces consistent indentation. Whether your team prefers two or four spaces, having the rule in place ensures everyone follows the same structure, preventing merge conflicts and visual confusion.

semi

The semi rule is another formatting-related setting that dictates whether semicolons are required at the end of statements.

While JavaScript allows you to omit them in many cases, enforcing a consistent semicolon policy can prevent bugs related to automatic semicolon insertion, which can behave unpredictably in some scenarios.

prefer-const

For developers working with modern JavaScript, the prefer-const rule is incredibly useful.

It suggests using const instead of let for variables that are never reassigned. This helps convey intent clearly and minimizes the risk of accidental reassignment, which can lead to hard-to-find bugs.

no-var

The no-var rule promotes the use of let and const over var. With the advent of ES6, var has become largely obsolete due to its function-scoping behavior, which often leads to confusing results. let and const are block-scoped and offer more predictable behavior, making your code easier to reason about.

no-param-reassign

A rule that emphasizes best practices in function handling is no-param-reassign. This rule prevents you from reassigning function parameters.

While it might seem convenient to modify parameters directly, doing so often leads to unexpected behavior, especially in asynchronous code or closures.

Copying the parameter to a new variable before changing it is generally the safer route.

curly

If you care about the clarity and structure of your code blocks, the curly rule is worth enabling. It enforces the use of curly braces for all control statements, even if they contain only a single line.

This might seem excessive, but it helps avoid bugs that occur when additional statements are added later and braces are forgotten.

arrow-body-style

The arrow-body-style rule encourages concise arrow functions when possible.

For example, instead of writing const add = (a, b) => { return a + b; }, it suggests simplifying it to const add = (a, b) => a + b;. This results in more succinct code that’s easier to scan and understand.

object-curly-spacing

Another rule that promotes better readability and maintainability is object-curly-spacing. This rule enforces consistent spacing inside curly braces of object literals and destructuring assignments.

Whether you choose { foo: bar } or {foo: bar}, what matters is consistency throughout the codebase.

comma-dangle

The comma-dangle rule might seem like a nitpick, but it has practical implications. It enforces or disallows trailing commas in object and array literals.

When enabled to require trailing commas, it makes diffs cleaner in version control and simplifies the process of adding new elements to these structures.

quotes

Among stylistic preferences, quotes is a useful rule for enforcing consistency in the use of single or double quotes. Again, the main value here is in uniformity, which reduces distractions and keeps the focus on what the code does rather than how it’s styled.

no-shadow

The no-shadow rule prevents variable declarations from shadowing variables declared in the outer scope.

Shadowing can make it extremely difficult to track which variable is being referenced, especially in larger functions or nested scopes.

Avoiding it reduces bugs and makes your code easier to debug.

A strong rule for clarity is consistent-return, which enforces that every code path in a function either returns a value or doesn’t return at all.

This prevents scenarios where some branches return a result and others return undefined, leading to inconsistent outcomes that can break your program.

default-case

The default-case rule ensures that switch statements have a default branch.

Even if you think you've handled every case, the default ensures your code behaves predictably if an unexpected value shows up. This is especially useful when dealing with external data or user inputs.

no-async-promise-executor

For async programming, the no-async-promise-executor rule is essential.

It disallows using async functions as Promise executors, which can cause unhandled rejections or misinterpreted promise behavior.

This rule protects developers from common pitfalls when working with asynchronous logic.

yoda

Finally, the yoda rule governs the style of conditional expressions, specifically the order of literals and variables.

While often a matter of preference, enforcing one approach across the codebase—typically placing variables on the left—improves code scanning and reduces cognitive overhead.

Conclusion

Each of these ESLint rules contributes something valuable to your codebase.

Together, they help enforce consistency, prevent subtle bugs, and promote best practices.

The key is not to enforce every rule but to choose the ones that align with your team's style and goals.

ESLint allows for fine-tuning, meaning you can warn, error, or turn off rules depending on the context.

Using ESLint effectively isn’t just about catching mistakes, it’s about codifying your development standards so that every contributor can write code that feels cohesive, clean, and professional.

Top comments (0)