ThisType<Type>

Marks an object literal's methods so this is contextually typed, without changing the type itself.

Signature
interface ThisType<T> { }
  • Added in TypeScript 2.3

Parameters

ParameterTypeDescription
$Tany typeThe type that `this` should have inside methods of the object being contextually typed by the intersection.

Return value

none — it is a marker, not a transformationNothing. Intersecting a type with `ThisType<T>` leaves the type unchanged and tells the checker that `this` inside contextually typed methods is `T`.

Errors

Nothing, but the marker only takes effect with `noImplicitThis` (included in `strict`) enabled; without it `this` stays implicitly `any`.

ThisType<T> is an empty interface. It adds no members, transforms nothing, and disappears at compile time. Its only job is to be intersected into the type of an object literal argument so the checker knows what this is inside that literal's methods.

The pattern is always the same: a function takes a descriptor with a data half and a methods half, merges them at runtime, and wants the methods to see the merged result. Write the methods property as M & ThisType<D & M> and every method body gets this typed as the merged object — this.x resolves, autocompletes, and is checked, even though no method declares a this parameter. This is how framework options objects (component definitions, mixin descriptors, Vue-style data/methods pairs) get their typing.

What trips people up

  • noImplicitThis must be on. Without it this is implicitly any and the marker appears to do nothing at all — the code compiles either way, which makes this a confusing bug.
  • It only works through contextual typing. Assign the object literal to an intermediate variable first and the context is lost.
  • It is not ThisParameterType's counterpart. That one reads an explicit this parameter off a function type; this one supplies this to methods that have no such parameter.

Example

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

When to use it

  • Type a `makeObject({ data, methods })` factory so methods can read and write the data fields.
  • Give a mixin or plugin descriptor object access to the merged instance through `this`.
  • Build a fluent configuration API whose callbacks operate on the object under construction.

Frequently asked questions

How do I type this inside methods of an object literal passed to a function?

Intersect the methods property with `ThisType<TheMergedType>` in the parameter's type, e.g. `methods?: M & ThisType<D & M>`. The methods then see the merged object as `this` with no per-method annotation.

Why is ThisType not doing anything in my project?

Almost always because `noImplicitThis` is off. The marker requires it (it is included in `strict`); without the flag `this` is implicitly `any`, so nothing is checked and nothing appears to change.

Does ThisType add properties or affect the runtime object?

No. It is an empty interface used purely as a compile-time marker, so intersecting with it changes neither the members of the type nor the emitted JavaScript.

More examples

The handbook descriptor, written out in full

Both `data` and `methods` are optional here, which is why the implementation defaults them. Inside `describe`, `this.x` is a `number` rather than an error under `noImplicitThis`, and the printed result is `(3, 8)` after the two moves.

Example · typescript
type ObjectDescriptor<D, M> = {
  data?: D;
  methods?: M & ThisType<D & M>; // Type of 'this' in methods is D & M
};

function makeObject<D, M>(desc: ObjectDescriptor<D, M>): D & M {
  const data: object = desc.data || {};
  const methods: object = desc.methods || {};
  return { ...data, ...methods } as D & M;
}

const obj = makeObject({
  data: { x: 0, y: 0 },
  methods: {
    moveBy(dx: number, dy: number) {
      this.x += dx; // strongly typed this
      this.y += dy;
    },
    describe() { return `(${this.x}, ${this.y})`; },
  },
});

obj.moveBy(5, 5);
obj.moveBy(-2, 3);
console.log(obj.describe());

A component-style options object

`this.items` inside `add` is `string[]` and `this.done` inside `complete` is `number`, derived purely from the sibling `state` property — no annotations inside the action bodies. Output: `1/2` followed by `[ 'write docs', 'review PR' ]`.

Example · typescript
type Options<S, A> = {
  state: S;
  actions: A & ThisType<S & A>;
};

function defineComponent<S, A>(opts: Options<S, A>): S & A {
  return Object.assign({}, opts.state, opts.actions) as S & A;
}

const todo = defineComponent({
  state: { items: [] as string[], done: 0 },
  actions: {
    add(title: string) { this.items.push(title); return this.items.length; },
    complete() { this.done += 1; return `${this.done}/${this.items.length}`; },
  },
});

todo.add("write docs");
todo.add("review PR");
console.log(todo.complete());
console.log(todo.items);

Discussion

  • Be the first to comment on this lesson.