error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. is reported when this is used in a function that is not a method of a class or an object literal, so the checker has no way to know what it will be. With noImplicitThis on (part of strict), that any is an error.
In browser JavaScript the typical case is a named function used as an event handler: addEventListener calls it with this set to the element. The checker does not read that from the later addEventListener call, because the function is declared on its own.
At a glance
| Code | TS2683 |
|---|---|
| Message | 'this' implicitly has type 'any' because it does not have a type annotation. |
| TypeScript's category | error |
| Listed under | Implicit any |
| Turned on by | noImplicitThis, strict |
| In .js files | Reported when the file is checked: checkJs in jsconfig.json, or // @ts-check at the top of the file |
The message is TypeScript's own text from its diagnostic messages file (Apache-2.0).
What it looks like
export function toggleOpen() {
this.classList.toggle("open");error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation.
}
document.querySelector("nav button")?.addEventListener("click", toggleOpen);jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} What causes it
- A function declaration or expression uses
thisand is not part of a class or object literal. noImplicitThisis on (part ofstrict).
How to fix it
Declare this with @this
/** @this {HTMLElement} */ above the function gives this a type. Calling the function some other way, without the right this, is then reported.
/** @this {HTMLElement} */
export function toggleOpen() {
this.classList.toggle("open");
}
document.querySelector("nav button")?.addEventListener("click", toggleOpen);
/** @param {Event} event */
export function toggleFromEvent(event) {
if (event.currentTarget instanceof HTMLElement) event.currentTarget.classList.toggle("open");
}jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} Or use the event instead of this
event.currentTarget is the element the listener is on. It is typed EventTarget | null, so check it with instanceof HTMLElement before using element properties. This also works in arrow functions, which have no this of their own.
Gotchas
- A function that assigns to
this.somethingis treated as a constructor function in a.jsfile, andthisinside it is not reported. - At the top level of a module,
thisisundefined; an arrow function there that usesthisgets a different error (the value may be undefined) rather than TS2683.
Sources
- JSDoc Reference: @this · TypeScript handbook
- TSConfig Reference: noImplicitThis · TypeScript
- Event: currentTarget property · MDN Web Docs
- diagnosticMessages.json (TypeScript 5.9.3) · TypeScript on GitHub
Last reviewed 20 October 2026.