Skip to content

this Types & Polymorphism

Inside a class, this is not only a value — it is a type that means “the type of the current instance.” Crucially, in a subclass this refers to the subclass, not the class where the method was written. This is the polymorphic this type, and it makes fluent APIs work correctly across inheritance.

A builder that returns this from each method lets calls chain. Typing the return as this (not the class name) means subclass methods stay chainable too.

class QueryBuilder {
private parts: string[] = [];
where(cond: string): this { // return type is `this`, not QueryBuilder
this.parts.push(cond);
return this;
}
}
class MySQLBuilder extends QueryBuilder {
limit(n: number): this {
return this;
}
}
new MySQLBuilder()
.where("a = 1") // returns MySQLBuilder (because of `this`), so...
.limit(10); // ...limit() is still available. ✅

If where had been typed to return QueryBuilder, the chain would “forget” it was a MySQLBuilder and .limit() would fail. Polymorphic this preserves the real type through the chain.

A function can declare a fake first parameter named this to type what this must be when the function is called. It is erased on emit and does not affect the real argument list — it exists purely to type-check the calling context.

interface Card { title: string; }
function render(this: Card) {
return this.title.toUpperCase();
}
// render(); // ❌ The 'this' context of type 'void' is not assignable...
render.call({ title: "hi" }); // ✅ this is a Card here

This catches a whole class of bugs where a method relies on a this it might not actually get.

The classic JavaScript footgun — passing a method as a callback and losing its this — has a type-level story too. When you pass obj.method by reference, the this binding is dropped:

class Counter {
count = 0;
increment() { this.count++; } // relies on `this`
}
const c = new Counter();
const fn = c.increment;
// fn(); // 💥 at runtime `this` is undefined

TypeScript can catch this when you opt in. The strictBindCallApply and (with a this parameter) the checker will flag an unbound method call. The idiomatic fixes are an arrow-function field (increment = () => { ... }, which binds this lexically) or binding at the call site (c.increment.bind(c)).

What does the `this` type mean inside a class method?
Why return `this` (rather than the class name) from a chainable builder method?
What is a `this` parameter used for?
What is an idiomatic fix for a method losing its `this` when passed as a callback?