TypeScript TS7006: Parameter 'x' implicitly has an 'any' type
Parameter implicitly has any type
Verified against TypeScript docs: Compiler Options — noImplicitAny, TypeScript handbook: Functions, TypeScript 5.5 release notes · Updated June 2026
> quick_fix
TypeScript can't figure out the type of a function parameter and noImplicitAny is enabled. Add an explicit type annotation to the parameter. If the function is a callback, TypeScript usually infers the type from context — check that the callback is passed to a properly typed function.
// TS7006: Parameter 'event' implicitly has an 'any' type
function handleClick(event) {
console.log(event.target)
}
// Fix: add a type annotation
function handleClick(event: MouseEvent) {
console.log(event.target)
}What causes this error
TS7006 fires when noImplicitAny is enabled (included in strict mode) and a function parameter has no explicit type annotation and TypeScript cannot infer its type from context. Without a type annotation or contextual typing (such as when a callback is passed to a typed function), the parameter defaults to 'any'. The noImplicitAny flag turns this silent default into a compile error.
How to fix it
- 01
step 1
Add an explicit type annotation
The direct fix is to declare the parameter's type. For DOM event handlers, use the appropriate Event subtype. For Express/Koa handlers, use the framework's request/response types. For generic callbacks, determine the type from the calling code.
// DOM events function handleSubmit(event: SubmitEvent) { /* ... */ } function handleInput(event: InputEvent) { /* ... */ } // Express import type { Request, Response } from 'express' function getUsers(req: Request, res: Response) { /* ... */ } // Generic callback function process(item: string, index: number) { /* ... */ } - 02
step 2
Let contextual typing infer the parameter type
When a function is passed as a callback to a typed function, TypeScript infers parameter types from the callback signature. If TS7006 fires on a callback, the issue is usually that the parent function isn't properly typed or the callback is defined separately.
// Inline callback — TypeScript infers 'user' as User const names = users.map(user => user.name) // OK: contextual typing // Separate function — no context, TS7006 fires function getName(user) { return user.name } // Error const names = users.map(getName) // Fix: type the standalone function function getName(user: User) { return user.name } // OK - 03
step 3
Type destructured parameters
Destructured parameters in function signatures need the type annotation on the whole parameter object, not on individual destructured names.
// TS7006 on destructured params function createUser({ name, email }) { // Error on name and email return { name, email } } // Fix: annotate the entire parameter object function createUser({ name, email }: { name: string; email: string }) { return { name, email } } // Or use a named type interface CreateUserInput { name: string; email: string } function createUser({ name, email }: CreateUserInput) { return { name, email } } - 04
step 4
Handle rest parameters and array callbacks
Rest parameters and some callback patterns lose contextual typing. Add explicit types to restore type safety.
// Rest params need a type function log(...args: unknown[]) { console.log(...args) } // reduce callback — TypeScript infers accumulator from initial value // but if initial value is ambiguous, annotate the callback const total = items.reduce( (sum: number, item: Item) => sum + item.price, 0 ) - 05
step 5
Use 'unknown' instead of 'any' for truly dynamic parameters
If a parameter genuinely accepts any type, annotate it as unknown rather than any. This preserves type safety by requiring narrowing before use, while still accepting all input types.
// Bad: explicit any disables all type checking function serialize(value: any): string { return JSON.stringify(value) // no checking inside } // Better: unknown requires narrowing function serialize(value: unknown): string { if (typeof value === 'object' && value !== null) { return JSON.stringify(value) } return String(value) }
How to verify the fix
- Run tsc --noEmit and confirm TS7006 no longer appears
- Check that added type annotations match the actual runtime values
- Verify no 'any' was used as a shortcut — prefer unknown for truly dynamic values
Why TS7006 happens at the runtime level
TS7006 is emitted during function declaration checking when the checker encounters a parameter with no type annotation and no contextual type. Contextual typing flows from the expected type of the expression containing the function — for example, a callback passed to Array.map receives contextual types from map's signature. When no contextual type exists (standalone function declarations, exported functions, top-level arrow functions assigned to untyped variables), and noImplicitAny is enabled, the checker emits TS7006 for each untyped parameter rather than silently defaulting to any.
Common debug mistakes for TS7006
- Defining event handlers as standalone functions instead of inline callbacks, losing contextual typing from addEventListener or React's onChange.
- Using ': any' as a quick fix instead of finding the correct type annotation.
- Forgetting to install @types packages for libraries, so callback parameter types aren't available.
- Typing destructured parameters on individual names instead of the whole parameter object.
- Defining utility functions without types and expecting TypeScript to infer from usage.
When TS7006 signals a deeper problem
A codebase with many TS7006 errors is usually a JavaScript project being migrated to TypeScript. The implicit-any parameters are the original untyped JavaScript code that hasn't been annotated yet. The migration strategy matters: adding 'any' everywhere passes the compiler but provides zero type safety. The right approach is to type the leaf functions first (utilities, helpers) and work outward to the API boundary functions last. This way, contextual typing flows inward and reduces the number of explicit annotations needed. Tools like ts-migrate can add initial annotations, but they default to 'any' — a human pass is needed to replace those with real types.
Editor's take
TS7006 is the migration error. When a team enables strict mode on an existing JavaScript-to-TypeScript project, TS7006 is typically the most frequent error, often numbering in the hundreds or thousands. Every untyped function parameter surfaces as its own error. The temptation is to batch-fix with ': any' and move on — and this is exactly the wrong thing to do.
The error exists because noImplicitAny draws a hard line: TypeScript will not silently pretend a value has type 'any'. Without this flag, untyped parameters become invisible holes in your type system. Code inside the function can access any property, call any method, and pass the value anywhere — all without a single type error. Bugs hide in these holes until they crash in production.
Contextual typing makes TS7006 less painful than it first appears. When you write users.map(u => u.name), TypeScript infers that u is User from the array's element type. You don't need to annotate callback parameters passed to properly typed functions. TS7006 only fires when there's no contextual type — meaning the function is standalone, exported, or passed to an untyped function. This is useful information: TS7006 identifies your type system's entry points, the places where types must be declared because they can't be inferred.
The worst TS7006 pattern is event handlers in React class components. Class methods don't get contextual typing from JSX props, so every onClick, onChange, and onSubmit handler needs an explicit event type annotation. This is one reason functional components with inline handlers are easier to type — the JSX attribute provides the contextual type automatically.
By Bikram Nath · Curator · Updated June 2026
Frequently asked questions
Should I just add ': any' to fix TS7006?
No. Adding an explicit 'any' annotation silences the error but defeats the purpose of TypeScript. The parameter becomes an untyped black hole where any operation is allowed without checking. Use a specific type if you know what the parameter should be, or 'unknown' if the parameter is genuinely dynamic. Explicit 'any' should be a last resort for interop with untyped JavaScript libraries, and even then, you should wrap it in a typed function boundary.
Why doesn't TypeScript infer the type from how I use the parameter inside the function?
TypeScript infers parameter types from contextual typing (the callback's position in a typed call), not from usage inside the function body. This is by design: inferring from usage would be fragile and could change based on refactors inside the function. The function signature is the contract, and TypeScript wants that contract to be explicit. If you add properties or methods to the parameter inside the function, that doesn't tell TypeScript what type the parameter should be — only what you assume it is.
Does TS7006 fire if noImplicitAny is disabled?
No. TS7006 only fires when noImplicitAny is true (which is included when strict is true). Without it, untyped parameters silently become 'any' and TypeScript skips all type checking for those values. This means bugs that TypeScript could catch — accessing non-existent properties, passing wrong argument types — go undetected. Every serious TypeScript project should enable noImplicitAny or strict mode.