noImplicitThis

Errors when this is used in a context where its type cannot be determined.

Signature
"noImplicitThis": boolean  // Default: true if strict; false otherwise
  • Added in TypeScript 2.0

Parameters

ParameterTypeDescription
$noImplicitThisoptionalboolean= true if strict; false otherwiseWhen true, raises an error on this expressions whose type would be an implied any.

Errors

Nothing at runtime; it reports error 2683, "'this' implicitly has type 'any' because it does not have a type annotation".

Changelog

  • PHP 2.0Introduced together with explicit this parameters, which are the annotation this flag asks for.
  • PHP 2.3ThisType<T> was added; contextual this typing through ThisType is only meaningful once this flag is on.

In JavaScript this is determined by the call, not the definition. A function expression pulled out of a class body gets whatever this the caller supplies — often undefined. Without this flag TypeScript types that this as any and lets you read any property off it.

How to satisfy it

  • Use an arrow function, which captures this lexically
  • Declare an explicit this parameter: function area(this: Rectangle) { ... } — it is a fake first parameter, erased at emit, and callers pass nothing for it
  • Type the surrounding object with ThisType<T> so members get a contextual this

What trips people up

The this parameter must come first and is not part of the call's arity, so fn(1) still passes 1 to the second declared parameter. The flag is also the prerequisite for the rest of the this machinery: ThisType, ThisParameterType and OmitThisParameter all describe something that has no meaning while every this is any. Class methods, object literal methods and getters already have a known this, so the errors cluster in extracted callbacks and prototype-style code.

Example

Example · typescript
class Rectangle {
  constructor(public width: number, public height: number) {}

  // return function () { return this.width * this.height; }
  // -> error 2683: 'this' implicitly has type 'any'
  getAreaFunction() {
    return () => this.width * this.height; // arrow captures `this`
  }
}

function area(this: Rectangle) {           // explicit this parameter
  return this.width * this.height;
}

const r = new Rectangle(3, 4);
console.log(r.getAreaFunction()()); // 12
console.log(area.call(r));          // 12

When to use it

  • Finding callbacks that reference this after being detached from their object
  • Typing a plugin or mixin API where methods run bound to a host object
  • Making a prototype-style JavaScript file check cleanly under checkJs

Frequently asked questions

How do I fix "'this' implicitly has type 'any'"?

Either convert the function expression to an arrow function so this is captured lexically, or declare an explicit this parameter such as function fn(this: Widget). Error 2683 comes from noImplicitThis.

What is a this parameter in TypeScript?

A fake first parameter named this that declares what the function expects this to be. It is erased at compile time, does not affect the number of real arguments, and lets call, apply and bind check the receiver.

Do I need noImplicitThis to use ThisType?

In practice yes. ThisType<T> supplies a contextual this for object literal members, which is only observable once implicit any this expressions are errors — with the flag off every this is already any and the helper changes nothing you can see.

More examples

The detached-callback crash

Prints 2. As a class field holding an arrow function, this is captured at construction, so detaching it is safe. Declared as a normal method, the same detachment throws at runtime and is exactly what noImplicitThis flags when the body is a function expression.

Example · typescript
class Counter {
  count = 0;

  // Written as `increment() { this.count++ }` and then passed as a
  // bare reference, `this` is undefined at the call site.
  increment = () => {
    this.count++;
  };
}

const c = new Counter();
const run = c.increment; // detached, but the arrow field captured `this`
run();
run();
console.log(c.count); // 2

A this parameter does not shift arity

All three print with the prefix applied first: order-7, inv-7, tmp-7. The this parameter is compile-time only, so bind produces (prefix: string) => string rather than a two-argument function.

Example · typescript
interface Row { id: number }

function label(this: Row, prefix: string) {
  return prefix + "-" + this.id;
}

const row: Row = { id: 7 };

// `prefix` is still the first real argument:
console.log(label.call(row, "order")); // order-7
console.log(label.apply(row, ["inv"])); // inv-7

const bound = label.bind(row);
console.log(bound("tmp")); // tmp-7

Discussion

  • Be the first to comment on this lesson.