TypeScript error

TS2684: A function called with the wrong this

  • Error TS2684
  • Tested with TypeScript 5.9

error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type 'HTMLButtonElement'. is reported when a function says what this must be, through a @this tag or a this parameter in its type, and a call gives it something else. A plain call, onSave(event), gives this the type void.

In JavaScript the same mistake surfaces at run time as TypeError: Cannot set properties of undefined in strict-mode code, or as a write to the global object in sloppy scripts.

At a glance

CodeTS2684
MessageThe 'this' context of type '{0}' is not assignable to method's 'this' of type '{1}'.
TypeScript's categoryerror
Listed underTypes do not match
Turned on by No option: every checked file reports it
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); {0} and {1} are filled in by tsc for each error.

What it looks like

save.js Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: save.js(11,1): error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type 'HTMLButtonElement'. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. save.js(11,1): error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type 'HTMLButtonElement'. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. save.js(11,1): error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type 'HTMLButtonElement'. checked 21 October 2026
/**
 * @this {HTMLButtonElement}
 * @param {MouseEvent} event
 */
function onSave(event) {
  this.disabled = true;
  console.log(event.type);
}

onSave(new MouseEvent("click"));error TS2684: The 'this' context of type 'void' is not assignable to method's 'this' of type 'HTMLButtonElement'.

export { onSave };
A function typed with @this, called without one.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["**/*.js"]
}

What causes it

  • An event handler or method that uses this is called directly instead of by the code that sets this (addEventListener, call, apply).
  • A method is taken off its object (const save = form.save) and called on its own.

How to fix it

Call it the way it expects

Pass the function to whatever sets this (addEventListener sets it to the element), or supply it yourself with call, apply or bind.

save.js TypeScript 5.9.3 TypeScript 5.9.3, run 21 October 2026: No errors. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. No errors. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. No errors. checked 21 October 2026
/**
 * @this {HTMLButtonElement}
 * @param {MouseEvent} event
 */
function onSave(event) {
  this.disabled = true;
  console.log(event.type);
}

const button = document.createElement("button");
button.addEventListener("click", onSave);
onSave.call(button, new MouseEvent("click"));

export { onSave };
Called by addEventListener, or with call(), it gets its this.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["**/*.js"]
}

Or stop relying on this

A handler can read the element from event.currentTarget instead, and a method can be bound once in the constructor or written as an arrow function field. Then it can be called any way, and the @this tag goes.

Gotchas

  • Passing a @this function to addEventListener on an element of another type was not reported in this site's tests: the listener overloads accept it. The check covers direct calls.
  • @this on an arrow function is a different error (TS2730), because arrows take this from where they are written.

Sources

Last reviewed 21 October 2026.