Skip to main content

Fixing Lint Errors

When pnpm lint reports an error, find the rule name at the end of the line in the tables below. Each row says what the error means in plain English and how to fix it.

src/userService.ts
12:3 error Dependency cycle detected import-x/no-cycle
│ │ └── the rule name — look this up below
│ └── the message
└── line 12, column 3

The golden rule​

Fix the code. Never switch the rule off to make the error go away.

A lint error means the code breaks a standard. The fix is always to change the code. Do not add eslint-disable comments, do not delete rules from the config, and do not move files into vendor/ to hide them.

There are exactly two rules that may be switched off for one line, and both need a comment saying why — see the only allowed exceptions.

This applies to everyone, including AI agents. An agent's work is not finished while pnpm lint reports errors.


Imports​

RuleWhat you will seeWhat it meansHow to fix it
import-x/no-cycleDependency cycle detectedTwo files import each other, directly or through other files. One will load before the other is readyMove the part both files need into a third file that both import. If the cycle goes through an index.ts, import the file directly instead. See Import safety
import-x/no-unresolvedUnable to resolve path to module '…'The file being imported does not exist at that pathCheck the spelling and the path. If the file was renamed or moved, update the import
import-x/no-default-exportPrefer named exportsThe file uses export defaultChange to a named export: export const formatCurrency = …
@typescript-eslint/consistent-type-importsAll imports in the declaration are only used as types. Use import typeA type is imported like a valueChange import { UserType } to import type { UserType }

Order and variables​

RuleWhat you will seeWhat it meansHow to fix it
no-use-before-define'formatReport' was used before it was definedSomething is used above the line that creates itMove the definition above the code that uses it
no-restricted-syntaxUse const. If this value really must be reassigned…A variable is declared with letChange let to const. If the value really must change, see the allowed exceptions
no-varUnexpected var, use let or const insteadA variable is declared with varChange var to const
prefer-const'total' is never reassigned. Use 'const' insteadA let variable never changesChange let to const
no-magic-numbersNo magic number: 3A bare number is used in the logicGive it a name: const MAXIMUM_RETRY_ATTEMPTS = 3;
unicorn/name-replacementsThe variable `btn` should be named `button` A name is shorthandRename it to the full English word
unicorn/no-top-level-side-effectsDo not use top-level side effects in exported modulesThe file runs code as it loadsPut the code inside a function and export the function

Functions​

RuleWhat you will seeWhat it meansHow to fix it
func-styleExpected a function expressionThe function keyword was usedRewrite as an arrow function: const name = () => { … };
prefer-arrow-callbackUnexpected function expressionA callback uses the function keywordRewrite the callback as an arrow function
no-restricted-syntaxUse an arrow functionconst name = function () {} was usedRewrite as const name = () => {}
no-restricted-syntaxUse a single object parameter when a function needs more than one valueA function has more than one parameterTake one object instead: ({ name, emailAddress }: CreateUserProps) =>
no-restricted-syntaxUse functions, not classesA class was usedRewrite it as functions
no-restricted-syntaxType a value where it is declared, not with satisfies afterwardssatisfies was used outside a story filePut the type on the declaration instead: const config: ConfigType = { … }
max-depthBlocks are nested too deeply (4). Maximum allowed is 3ifs and loops are nested more than three deepReturn early for the error cases, or move the inner part into its own function
no-nested-ternaryDo not nest ternary expressionsA ? : sits inside another ? :Use an if, or move it into its own function

Files​

RuleWhat you will seeWhat it meansHow to fix it
max-linesFile has too many lines (312). Maximum allowed is 300The file is over 300 linesSplit it: move functions to utils/, sub-components to their own folders, types to types.ts. routes.ts, strings.ts, numbers.ts and noData.ts in lib/constants/ never get this error
unicorn/filename-caseFilename is not in camel case or pascal caseThe file name is in the wrong caseRename it: camelCase for code files, PascalCase for component files

Types​

RuleWhat you will seeWhat it meansHow to fix it
@typescript-eslint/no-explicit-anyUnexpected any. Specify a different typeany was usedUse the real type, or unknown and then check it
@typescript-eslint/no-non-null-assertionForbidden non-null assertionvalue! was usedCheck that the value exists first: if (!value) { return; }
@typescript-eslint/consistent-type-assertionsDo not use any type assertionsvalue as SomeType was usedValidate the value instead. If a cast is truly needed, see the allowed exceptions
@typescript-eslint/naming-conventionInterface name `User` must match the RegExp: /(Props|Type)$/uA type name does not end in Props or TypeRename it: UserType, ButtonProps

React​

RuleWhat you will seeWhat it meansHow to fix it
react/jsx-no-bindJSX props should not use arrow functionsA function is written inside the JSX, or passed without useCallbackDeclare it above with useCallback and pass it by name
react/no-multi-compDeclare only one React component per fileThe file has more than one componentMove the second component to its own folder
react/function-component-definitionAn error naming this ruleA component is written with the function keywordRewrite it as an arrow function. pnpm lint:fix does this automatically

Comments​

RuleWhat you will seeWhat it meansHow to fix it
@eslint-community/eslint-comments/require-descriptionUnexpected undescribed directive comment. Include descriptions to explain why the comment is necessaryAn eslint-disable comment has no reasonAdd the reason after --. Better: remove the comment and fix the code

The only allowed exceptions​

Two rules may be switched off for a single line. Both need the reason written after --, and ESLint rejects the comment without one.

A variable that must be reassigned​

Always use const. When a value genuinely has to change — a running total, a retry counter — use let and say why:

// eslint-disable-next-line no-restricted-syntax -- the running total is built up across the loop
let runningTotal = 0;

Before reaching for let, check whether const with map, filter or reduce does the job. It usually does.

A type cast that cannot be avoided​

// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- the API returns untyped JSON; validated by parseUser below
const user = response.data as UserType;

Nothing else is switched off. If another rule seems impossible to satisfy, the code needs restructuring — ask before disabling it.


Errors that stop ESLint running​

What you will seeWhat it meansHow to fix it
typescript-eslint does not support TS 7.0The linter cannot run against TypeScript 7 yetSee the TypeScript 7 note on the ESLint page
contextOrFilename.getFilename is not a functionThe React plugin cannot detect the React versionSet settings.react.version to the project's React version instead of "detect"
Cannot find module '…'A lint package is not installedRun the install commands on the ESLint page

When lint must pass​

Work is not finished until pnpm lint passes. That goes for people and AI agents alike: an agent fixes every lint error before it says a task is done.

Most projects check it automatically on every change, with a CI job that runs pnpm lint (often with pnpm test and the build) or with a git hook. Which one, if any, is the project's own choice. See Project workflow.