Unexpected any. Specify a different type: fix or disable
Make @typescript-eslint/no-explicit-any go quiet for the right reason: a scoped disable that ESLint actually reads, a config override, or a real type.
TL;DR#
Unexpected any. Specify a different type is reported by the @typescript-eslint/no-explicit-any rule whenever the keyword any appears in a type position. The comment from the original Stack Overflow question, // eslint:@typescript-eslint/no-explicit-any: "off", is ignored because ESLint does not read rule configuration from line comments. Either use a directive ESLint does read (// eslint-disable-next-line @typescript-eslint/no-explicit-any), switch the rule off in your config file, or replace any with unknown or a real type, which is what a zero-warnings policy actually asks for.
The message, as printed by a project on the current toolchain:
/app/a-plain.ts
1:23 error Unexpected any. Specify a different type @typescript-eslint/no-explicit-any
✖ 1 problem (1 error, 0 warnings)On an older project the same line says warning instead of error. The difference is explained below.
Why the rule fires, and why the comment did nothing#
The rule is part of typescript-eslint's recommended config. Its documentation describes any as a dangerous "escape hatch" from the type system and says the rule "reports on explicit uses of the any keyword as a type annotation". The message text comes straight from the rule source: unexpectedAny: 'Unexpected any. Specify a different type.'. noImplicitAny in tsconfig.json does not help here; the rule's docs point out that the compiler option "prevents an implied any, but doesn't prevent any from being explicitly used the way this rule does."
The asker saw warning; current projects see error. Comparing the recommended config at two tags of the typescript-eslint repository: the last 5.x release, 5.62.0 has '@typescript-eslint/no-explicit-any': 'warn', and the first major-6 release has '@typescript-eslint/no-explicit-any': 'error'. A warning does not fail eslint on its own (exit code 0 in the test), but a zero-issues policy enforced with --max-warnings 0 turns it into a failure:
/work/a-plain.ts
1:23 warning Unexpected any. Specify a different type @typescript-eslint/no-explicit-any
✖ 1 problem (0 errors, 1 warning)
ESLint found too many warnings (maximum: 0).The comment fails for two separate reasons.
- It is a line comment. ESLint accepts only two directives in
//comments:eslint-disable-lineandeslint-disable-next-line. Everything else, includingeslint rule: "off", must be a/* */block comment. The ESLint source states it in a comment, "only certain comment types are supported as line comments", and then skips any otherLinedirective. The ESLint rules documentation shows configuration comments only as block comments, such as/* eslint eqeqeq: "off", curly: "error" */. - The label is wrong. The directive is
eslintfollowed by a space, then the rules.eslint:@typescript-eslint/no-explicit-anyis not a known directive, so even inside/* */it does nothing.
Both were reproduced. With the typescript-eslint recommended flat config, ESLint 10.12.0 and typescript-eslint 8.71.1 (official node:22 Docker image, 7 October 2026), each of these files still reported the error on line 2:
// eslint:@typescript-eslint/no-explicit-any: "off"
export const payload: any = JSON.parse('{"city":"Leeds"}');// eslint @typescript-eslint/no-explicit-any: "off"
export const payload: any = JSON.parse('{"city":"Leeds"}');/* eslint:@typescript-eslint/no-explicit-any: "off" */
export const payload: any = JSON.parse('{"city":"Leeds"}');/app/j-op-block.ts
2:23 error Unexpected any. Specify a different type @typescript-eslint/no-explicit-any
✖ 1 problem (1 error, 0 warnings)The same comment written as a block comment with a space, /* eslint @typescript-eslint/no-explicit-any: "off" */, linted clean (exit code 0).
Fix#
Pick the narrowest option that matches the reason the any is there. Each step below was run on the setup described above.
1. Replace any with unknown or a real type (preferred)#
A zero-issues policy is satisfied best by removing the any. When the shape is known, describe it with an interface or type. When it is not, use unknown, which the rule's docs recommend as "the safer unknown type":
export const payload: unknown = JSON.parse('{"city":"Leeds"}');That file lints with no output and exit code 0. unknown does not let you read properties until you narrow the value, so the code that uses it changes too:
const payload: unknown = JSON.parse('{"city":"Leeds"}');
if (typeof payload === 'object' && payload !== null && 'city' in payload) {
console.log(payload.city);
}The third answer on the Stack Overflow thread suggests Record<string, unknown> for "any object" and index signatures for objects with arbitrary keys. The typescript-eslint docs list the same alternatives: index signatures, union types, and never or unknown in generic constraints, for example type AnyFunction = (...args: never[]) => unknown;.
2. Disable the rule for one line, with a reason#
When the any is genuinely needed (an untyped third-party package, code still being migrated), the rule's own docs suggest ESLint disable comments "for those specific situations instead of completely disabling this rule":
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- legacy SDK has no types
export const payload: any = JSON.parse('{"city":"Leeds"}');The text after -- is a description; ESLint's docs require it to be "separated from the configuration by two or more consecutive - characters". This is a line comment, and it works because eslint-disable-next-line is one of the two directives allowed in // form.
3. Disable it for a whole file#
At the very top of the file, as a block comment:
/* eslint-disable @typescript-eslint/no-explicit-any */
export const payload: any = JSON.parse('{"city":"Leeds"}');This is the second Stack Overflow answer, and it still works on ESLint 10. It is wide: every future any in that file passes silently.
4. Turn it off, or tune it, in the config file#
The first Stack Overflow answer sets the rule to off in .eslintrc.json. On a legacy config this works. With typescript-eslint 5.62.0 and ESLint 8.57.1, adding this to the .eslintrc.json that extends plugin:@typescript-eslint/recommended silenced the warning:
{
"root": true,
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint"],
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
"rules": {
"@typescript-eslint/no-explicit-any": "off"
}
}Current projects use a flat config, eslint.config.mjs. There, order matters: a later object wins. This switches the rule off (the example uses ESLint's defineConfig, because typescript-eslint marks its own tseslint.config() helper as deprecated in favour of it, in the helper's source):
import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';
export default defineConfig(
...tseslint.configs.recommended,
{
rules: {
'@typescript-eslint/no-explicit-any': 'off',
},
},
);Placing the same rules object before ...tseslint.configs.recommended does nothing: the recommended config, which comes later, sets the rule back to error, and the error reappeared in the test.
Rather than switching it off, the rule has two options. ignoreRestArgs allows ...args: any[], and fixToUnknown lets eslint --fix rewrite : any to : unknown (by default the rule only offers that change as an editor suggestion):
import { defineConfig } from 'eslint/config';
import tseslint from 'typescript-eslint';
export default defineConfig(
...tseslint.configs.recommended,
{
rules: {
'@typescript-eslint/no-explicit-any': [
'error',
{ ignoreRestArgs: true, fixToUnknown: true },
],
},
},
);With that config, export function log(...args: any[]): void linted clean, and eslint --fix turned the payload: any line into:
export const payload: unknown = JSON.parse('{"city":"Leeds"}');The docs warn that switching to unknown "is likely to cause additional type errors", which is the next section.
Verify the fix#
Run ESLint the way your CI does. If the policy is "zero warnings", that means --max-warnings 0:
npx eslint --max-warnings 0 src
echo "exit=$?"An exit code of 0 with no output means the rule is satisfied. If you used unknown, also run the compiler, because ESLint does not type-check:
npx tsc --noEmitOne email a month — the latest explained errors
What the site published that month — mostly Next.js, Supabase and Node errors, explained. You confirm by email; unsubscribe any time in one click.
After switching to unknown: TS18046 and stale disable comments#
Two follow-up errors are common once the any is gone.
The compiler now refuses property access. Reading payload.city on an un-narrowed unknown produced this with tsc --strict on TypeScript 6.0.3:
k-unknown-use.ts(2,13): error TS18046: 'payload' is of type 'unknown'.That is unknown doing its job. Narrow the value (the typeof and in checks in step 1 compiled with exit code 0) or give it a real type. If you type the value as an object instead and then read it with a variable typed as plain string, the compiler reports Element implicitly has an 'any' type: that is TS7053, which has its own fix.
A leftover disable comment becomes a new warning. If you change the type but keep the eslint-disable-next-line above it, ESLint 10.12.0 reports the directive itself. This is the output of npx eslint --max-warnings 0 on such a file:
/app/h-stale-directive.ts
1:1 warning Unused eslint-disable directive (no problems were reported from '@typescript-eslint/no-explicit-any')
✖ 1 problem (0 errors, 1 warning)
0 errors and 1 warning potentially fixable with the `--fix` option.
ESLint found too many warnings (maximum: 0).The current ESLint docs say reportUnusedDisableDirectives "defaults to "warn"", so on the version tested the stale comment fails a --max-warnings 0 run just as the original any did. This was not tested on the older ESLint 8 setup. Delete the comment, or let eslint --fix remove it, as the output suggests.
Upgrades, flat config and the severity change#
If the warning turned into an error after a dependency bump, the cause is the typescript-eslint major upgrade from 5 to 6, not your code. The same upgrade is the fix for an unrelated parser crash, covered in the 'originalKeywordKind' DeprecationError page. Next.js projects moving to eslint.config.mjs with ESLint 9 can follow the next lint removal guide; the same ordering rule applies there, so put the override after any preset that enables the rule. And if the any you are trying to remove is a (window as any) cast, declaring the property on Window removes the need for it.
The short version for a strict team: the message never needs a bypass that ESLint cannot read. A real type or unknown clears it permanently; a scoped eslint-disable-next-line with a reason documents the exceptions; and a config-level off placed after the recommended preset is the blunt option when the whole codebase is not ready.
Further reading: Fix: Jest SyntaxError Unexpected token export (uuid library).
Frequently Asked Questions
Still stuck? Paste your error.
Paste the error message or stack trace — we check it against every fix and tool on the site.
Continue Reading
Fix 'originalKeywordKind' DeprecationError in TypeScript
The 'originalKeywordKind' DeprecationError fires when @typescript-eslint packages are stuck on v5 while TypeScript moved on. Upgrade to v6.x and restart ESLint to clear it.
Fix ESLint: Module.createRequire is not a function
Reproduced on Node 10 vs Node 18 with the same node_modules: the crash is the Node runtime executing ESLint, not Parcel or a broken module resolution.
Prettier and ESLint Indent Rules Conflicting: the Fix
Stop fighting indent: Expected indentation of 2 spaces but found 4 by turning off the rule that conflicts with Prettier, not by retuning it.


