Guide to Resolving the “no-explicit-any” ESLint Error in Next.js

LightNode
By LightNode ·

Introduction

no explicit any

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.

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