this parameter

Types the this value of a function through a fake first parameter that is erased on emit.

Signature
function fn(this: SomeType, x: number) { /* ... */ }

class C {
  method(this: C): void { }
}

type Callback = (this: Element, event: string) => void;
  • Added in TypeScript 2.0

Parameters

ParameterTypeDescription
$thisSomeTypeMust be the very first parameter. It declares what the function's receiver has to be, is checked at call sites and on assignment, and is removed entirely from the emitted JavaScript.
$xoptionalnumberThe real parameters follow. Because `this` is erased, the first real parameter is still argument zero at runtime.

Errors

Calling the function with an incompatible receiver is an error ("The 'this' context of type X is not assignable to method's 'this' of type Y"), as is declaring a this parameter on an arrow function, which has no receiver of its own.

Changelog

  • PHP 2.0this parameters introduced alongside --noImplicitThis.
  • PHP 3.2--strictBindCallApply makes call, apply and bind check the this parameter and the argument list instead of accepting anything.

JavaScript forbids a parameter literally named this, so TypeScript borrows that syntax slot to declare the receiver's type. It must come first, it is checked at every call site, and it vanishes on emit — the compiled function has one fewer parameter than the source appears to.

When to reach for it

  • Callback APIs where the caller decides the receiver: event handlers, jQuery-style plugins, Mocha's function () { this.timeout() }.
  • Guarding a method against being torn off its instance — annotate method(this: MyClass) and passing obj.method as a bare callback becomes an error.
  • Declaring this: void to state that a function must not depend on a receiver, which is the honest signature for most standalone helpers.

What trips people up

Arrow functions cannot have one, because they close over the enclosing this instead of receiving their own; converting a function callback to an arrow silently changes what this means. Because the parameter is erased, it does not count toward fn.length, it does not appear in Parameters<typeof fn> (use ThisParameterType and OmitThisParameter for that), and .call() passes the receiver as its own first argument, not as a normal one. Checking on call, apply and bind only happens under strictBindCallApply.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Type the receiver inside an event-handler or plugin callback the framework invokes for you.
  • Stop a method from being passed as a bare callback by declaring `this: MyClass` on it.
  • Mark a standalone helper `this: void` so it cannot quietly start depending on a receiver.

Frequently asked questions

What is the this parameter in TypeScript?

It is a fake first parameter named `this` that declares what the function's receiver must be. JavaScript does not allow a parameter with that name, so TypeScript reuses the syntax for a type annotation and erases it when compiling.

Why can't I use a this parameter on an arrow function?

Because arrow functions do not have their own `this` — they capture the enclosing scope's — so there is no receiver to type. Use a `function` expression when the API you are passing the callback to decides the receiver.

Does the this parameter exist at runtime?

No. It is erased on emit, so it does not count toward fn.length, does not appear in Parameters<typeof fn>, and is not passed as an ordinary argument — you supply it through call, apply or bind. Use ThisParameterType and OmitThisParameter to work with it at the type level.

More examples

Guarding a method against being torn off

Prints "[utc]" four times. The commented-out call is what the annotation buys: without it, passing c.describe to setTimeout or an array method would compile and then fail at runtime with "Cannot read properties of undefined". ThisParameterType extracts the receiver type, and OmitThisParameter gives the already-bound signature.

Example · typescript
class Clock {
  constructor(private label: string) {}

  // `this: Clock` makes a detached call a compile error.
  describe(this: Clock): string {
    return `[${this.label}]`;
  }
}

const c = new Clock("utc");
console.log(c.describe());

const detached = c.describe;
// detached();
// Error: The 'this' context of type 'void' is not assignable to method's
// 'this' of type 'Clock'.

console.log(detached.call(c));
console.log(c.describe.bind(c)());

type Described = ThisParameterType<typeof c.describe>;   // Clock
type Free = OmitThisParameter<typeof c.describe>;        // () => string
const free: Free = c.describe.bind(c);
console.log(free());

Callback APIs that choose the receiver

Prints "toolbar handled click (1)" then "toolbar handled blur (1)". The this parameter on the Handler type flows into the anonymous function expressions, so `this.name` and `this.clicks` are typed without the caller writing an annotation. The commented-out arrow function is the classic mistake: it has no receiver of its own to type.

Example · typescript
interface Handler<T> {
  (this: T, event: string): void;
}

function on<T extends object>(target: T, handler: Handler<T>, event: string): void {
  handler.call(target, event);
}

const widget = { name: "toolbar", clicks: 0 };

on(widget, function (event) {
  // `this` is inferred as the widget — no annotation needed at the call site
  this.clicks++;
  console.log(`${this.name} handled ${event} (${this.clicks})`);
}, "click");

on(widget, function (event) {
  console.log(`${this.name} handled ${event} (${this.clicks})`);
}, "blur");

// on(widget, (event) => console.log(this.name), "click");
// An arrow function captures the enclosing `this`, so it cannot satisfy Handler<T>.

Discussion

  • Be the first to comment on this lesson.