Typing this in Functions
In JavaScript, the value of this inside a function depends on how the function is called, not where it is defined — a frequent source of bugs. TypeScript lets you type that calling context with a special fake this parameter: a parameter named this listed first in the signature. It exists only at compile time, is erased from the emitted JavaScript, and never counts as a real argument. This page covers declaring the this parameter, the utility types ThisParameterType and OmitThisParameter, and the noImplicitThis flag that surfaces unsafe usage.
The fake this parameter
You declare the expected context by adding this: Type as the very first parameter. It is purely a type annotation — callers still pass arguments starting from the second parameter.
interface Card {
suit: string;
value: number;
}
interface Deck {
cards: Card[];
describe(this: Deck): string;
}
const deck: Deck = {
cards: [{ suit: "♠", value: 1 }],
describe(this: Deck) {
return `Deck of ${this.cards.length} cards`;
},
};
deck.describe(); // ✅ called with the right context
Because this is the first parameter, describe still takes zero real arguments. TypeScript now checks that every call has a compatible receiver.
Catching the wrong context
The point of typing this is to reject calls where the context would be wrong at runtime — most commonly when a method is detached from its object and invoked standalone.
const describe = deck.describe;
// ❌ Error: The 'this' context of type 'void' is not assignable
// to method's 'this' of type 'Deck'.
describe();
Pulling deck.describe into a bare variable loses the receiver, so calling it would make this undefined. The typed this parameter turns that latent runtime crash into a compile error.
Callbacks and the this type
The this parameter is especially valuable for callback APIs that invoke your function with a specific context — for example, older DOM event handlers where this is the element.
interface ClickHandler {
(this: HTMLButtonElement, event: MouseEvent): void;
}
const onClick: ClickHandler = function (event) {
this.disabled = true; // this: HTMLButtonElement
console.log(event.clientX);
};
button.addEventListener("click", onClick);
Arrow functions have no
thisof their own — they capture it lexically — so you cannot declare athisparameter on one. Use afunctionexpression when an API setsthisfor you.
ThisParameterType and OmitThisParameter
Two built-in utility types let you work with the declared context. ThisParameterType<T> extracts the this parameter’s type (or unknown if none), and OmitThisParameter<T> removes it, producing the type you would get after binding.
function describeDeck(this: Deck): string {
return `Deck of ${this.cards.length} cards`;
}
type Ctx = ThisParameterType<typeof describeDeck>; // Deck
type Bound = OmitThisParameter<typeof describeDeck>; // () => string
const bound: Bound = describeDeck.bind(deck);
bound(); // no context required anymore
OmitThisParameter mirrors what Function.prototype.bind does at runtime: once bound, the function no longer needs (or accepts) an external this.
this types in classes and fluent APIs
Inside a class, the polymorphic this type (lowercase, distinct from the parameter) refers to the current instance type and powers fluent, chainable builders that return subclasses correctly.
class QueryBuilder {
private parts: string[] = [];
where(clause: string): this {
this.parts.push(clause);
return this;
}
}
class AdminQuery extends QueryBuilder {
asAdmin(): this {
return this;
}
}
new AdminQuery().where("active = 1").asAdmin(); // stays AdminQuery
Returning this rather than QueryBuilder keeps the subclass type through the chain.
Comparison of this-related constructs
| Construct | Purpose |
|---|---|
this: T parameter | Declare the required calling context (erased at runtime) |
this return type | Enable fluent chaining that preserves the subclass |
ThisParameterType<T> | Extract the declared context type |
OmitThisParameter<T> | Produce the post-bind signature |
noImplicitThis | Flag functions where this is implicitly any |
Enable noImplicitThis (included in strict) so any function relying on an untyped this becomes an error you must resolve explicitly.
Best Practices
- Declare a
this: Typeparameter whenever a function depends on its calling context. - Remember the
thisparameter is fake — it is erased and never counts as a real argument. - Use
functionexpressions, not arrow functions, when an API suppliesthisfor you. - Enable
noImplicitThis(viastrict) to catch unsafe implicitthisusage. - Return
thisfrom chainable methods so subclasses preserve their type through fluent calls. - Reach for
OmitThisParameterto type the result ofbind, andThisParameterTypeto extract a context.