Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript error: An outer value of 'this' is shadowed by this container

I had an error in a Typescript class method declaration, but I don't understand how the error message relates back to the bug.

The message seems to be saying that 'this' is of type any, but we are in a class definition, and so I thought 'this' was really clear.

Can someone please explain how the error message relates back to the bug?

Original method:

calcSize = function() {
    return this.width * this.length; // Error on this line
};

// Error text: 'this' implicitly has type 'any' because it does not 
//have a type annotation.ts(2683)
//app.ts(39, 16): An outer value of 'this' is shadowed by this container.

fix:

calcSize() {
    return this.width * this.length;
};

Full context (fixed):

class BaseObject {
    constructor(
        public width: number = 0,
        public length: number = 0
        ) {}

};

class Rectangle extends BaseObject {

    constructor(public width: number = 0, public length: number = 0) {
        super(width, length);
    }

    calcSize() {
        return this.width * this.length;
    };
}
like image 623
cham Avatar asked May 19 '19 02:05

cham


Video Answer


2 Answers

In TypeScript (and ES6) exists two kinds of functions: The classic function declaration and the arrow function. Where the classic function declaration has the default floating binding logic for the this keyword - the arrow function will constantly use the value for this of the context containing the arrow function. In the example this will be the instance of the surrounding class.

class Rectangle extends BaseObject {
// ..
  calcSize = function() {
    // the keyword function will cause this to be floating
    // since the function is explicitly assigned to calcSize
    // (older) TypeScript may not infer the type of this.
    // the value of this can be re-bind by changing the context
    // using bind or call
    // -> Value of this defaults to the class instance
    return this.width * this.length; // (potential) type Error on this line
  };
  calcSizeAsMember () {
    // is also a classic function which will use floating binding
    // therefore this will be the type of the containing class
    // the value of this can be re-bind by changing the context
    // using bind or call
    // -> Value of this defaults to the class instance
    return this.width * this.length; 
  };
  calcSizeAsArrowFunction = () => {
    // is an arrow function which has a constantly bind this keyword, 
    // it is not possible to change the binding afterwords (not re-binding)
    // type of this is constantly the type of the containing class
    // changing the context, use bind or call will have no effect
    // -> this will always remain to the instance of the class
    return this.width * this.length; 
  };
};
like image 63
Matthias Fischer Avatar answered Oct 02 '22 14:10

Matthias Fischer


After doing some research, I found a few interesting things. "this" can be a parameter of a regular function (not arrow function) and type can be either "any" or "unknown"

Notice the type "any" for "this" when declaring the function.

export async function main(this: any) {
    try {
        console.log(this);
    } catch (e: any) {

    }
}
like image 30
Wolfgang Leon Avatar answered Oct 02 '22 15:10

Wolfgang Leon