Guide to Resolving the “no-explicit-any” ESLint Error in Next.js
Introduction
TypeScript’s any
type bypasses all compile-time checks, negating the benefits of static typing. To enforce stronger type safety, the ESLint rule @typescript-eslint/no-explicit-any
flags any usage of any
. In Next.js apps with TS, you might encounter errors such as:
./src/lib/types/resource.ts
24:14 Error: Unexpected any. Specify a different type. @typescript-eslint/no-explicit-any
28:11 Error: Unexpected any. Specify a different type. @typescript-eslint/no-explicit-any
30:14 Error: Unexpected any. Specify a different type. @typescript-eslint/no-explicit-any
info - Need to disable some ESLint rules? Learn more here: https://nextjs.org/docs/app/api-reference/config/eslint#disabling-rules
// Example causing no-explicit-any:
function fetchData(url: string): Promise<any> {
return fetch(url).then(res => res.json());
}
Unchecked any
usage can lead to runtime bugs and obscure interfaces, undermining code maintainability. This guide prioritizes configuring ESLint in Next.js to control or disable the rule, then covers safer alternatives.
Understanding the Root Cause
What no-explicit-any
Enforces
The rule prevents explicit : any
annotations and implicit fallbacks to any
. It ensures you always declare precise types or use safer alternatives like unknown
.
Next.js’s Default TypeScript ESLint Setup
Next.js extends plugin:@typescript-eslint/recommended
by default. That preset includes:
"rules": {
"@typescript-eslint/no-explicit-any": "error"
}
As a result, any any
annotation—explicit or inferred—triggers an ESLint violation during development or build.
When This Error Is Most Prevalent
- Quick Prototypes: Developers may default to
any
to ship features faster. - Third-party Data: JSON or API responses without type definitions often start as
any
. - Migration Projects: Adding TypeScript to existing Next.js codebases can introduce many
any
usages.
Recommended Solution: Configuring ESLint in Next.js
Adjusting .eslintrc.js
Globally
To relax or disable the rule project-wide, update your .eslintrc.js
:
module.exports = {
extends: ["next/core-web-vitals", "plugin:@typescript-eslint/recommended"],
rules: {
"@typescript-eslint/no-explicit-any": "off", // turn off the rule
// or to warn instead of error:
// "@typescript-eslint/no-explicit-any": "warn",
},
};
Tuning via next.config.js
If you only want to bypass lint errors during production builds, modify next.config.js
:
module.exports = {
eslint: {
ignoreDuringBuilds: true, // skips all ESLint errors at build time
},
};
⚠️ This silences every ESLint error on build; use cautiously.
Disabling the Rule per File or Block
For targeted suppression, add inline ESLint comments:
/* eslint-disable @typescript-eslint/no-explicit-any */
function legacyHandler(payload: any) {
// ...implementation
}
/* eslint-enable @typescript-eslint/no-explicit-any */
Or disable for a single line:
const data: any = fetchSomething(); // eslint-disable-line @typescript-eslint/no-explicit-any
TypeScript-Specific Configurations
If you maintain a separate tsconfig.json
for linting, ensure it includes:
{
"compilerOptions": {
"noImplicitAny": true, // catches implicit any at compile time
// other strict flags...
}
}
Then align ESLint with your TS config:
// .eslintrc.js
parserOptions: {
project: ['./tsconfig.json'],
},
Alternative Solutions
When stricter typing is desired, consider these patterns instead of disabling the rule:
- Use
unknown
: Forces type-checking before use.async function fetchData(): Promise<unknown> { const res = await fetch('/api/data'); return res.json(); }
- Define Interfaces: Model API responses explicitly.
interface User { id: number; name: string; } async function getUser(): Promise<User> { /* ... */ }
- Generics: Make utilities reusable with types.
function fetchTyped<T>(url: string): Promise<T> { /* ... */ }
Other Practical Workarounds
Gradual Typing with // @ts-ignore
For one-off scenarios, suppress TypeScript errors:
// @ts-ignore
const result = legacyFunction();
Type Assertions
Assert a more specific type when you know it:
const value = (obj as MyType).property;
Creating Custom ESLint Overrides
For test files or mocks, add overrides in .eslintrc.js
:
module.exports = {
overrides: [
{
files: ['**/*.test.ts', '**/*.spec.ts'],
rules: {
'@typescript-eslint/no-explicit-any': 'off',
},
},
],
};
Summary & Reference Resources
Solution | Pros | Cons |
---|---|---|
Disabling ESLint rule globally | Fastest fix, zero lint noise | Masks all explicit-any issues |
Using unknown |
Retains type-safety, explicit checks | Requires extra type-checking boilerplate |
Defining interfaces & generics | Strong typing, self-documenting code | More upfront effort |
Inline disables or overrides | Granular control | Scatters directives in code |