8

What's the expected behavior when using this inside a function in an object literal?

For example, let's say I have a type foo that only has a function named bar and no other property on it. But in the fooObj.bar method, I'm able to access this.baz (where baz is not a property on type foo) I see no error. Shouldn't typescript error out, as fooObj does not have baz on it?

type foo = {
    bar(): void;
}
var fooObj: foo = {
    bar: () => {
        // TS does not error out when I access this.baz
        console.log(this.baz);
    }
} 

3 Answers3

7

Setting the "noImplicitThis": true compiler option is how you would enable this functionality now. This pull request enabled typed this in object literals. Aleksey L originally suggested this compiler option in a comment on the question, but at the time it didn't function that way.

alienriver49
  • 682
  • 12
  • 18
  • 2
    This is the actual solution. `noImplicitThis` makes the `this` keyword work the way that you would expect, in an object literal. – Andrew Koster Oct 20 '20 at 17:43
3

You’re using an arrow function, which has lexical this.

The shorthand for a non-arrow function property in an object literal is even shorter, though:

var fooObj: foo = {
    bar() {
        console.log(this.baz);
    }
}
Ry-
  • 218,210
  • 55
  • 464
  • 476
  • The question remains: What is `baz` and why isn't TypeScript telling you that `foo` (which should be the type of `this` I think) doesn't have a `baz` property? I'm not super knowledgable about TypeScript, but isn't the whole point that your types need to explicitly define their properties? I guess the question is, why is `this` of type `any` inside a lexically bound function, and not of type `foo`? – user229044 Oct 26 '16 at 17:45
  • 1
    @meagar: `foo` shouldn’t be the type of `this`. `this` will be whatever `this` was in the function containing the object literal. – Ry- Oct 26 '16 at 17:53
  • Ah, yeah. I glossed over the fact that we're not in an ES6 class declaration. Why then, does TypeScript not look at the context of the object literal declaration and see that whatever type `this` is still doesn't have a `baz` property? – user229044 Oct 26 '16 at 18:38
  • @meagar Because `this` is the global scope in that code, which is `any`. – Alex Oct 26 '16 at 19:34
  • Yeah, I missed the subtleties of using an arrow function. But even when I try using non-arrow function, "this" resolves to "any" as opposed to foo. This allows for access to properties that are not defined inside the object literal. – Arvind Venkataraman Oct 26 '16 at 23:29
3

This answer was true at the time of the question. This have since changed with new versions of typescript and target javascript versions.

You are asking typescript to infer that this is fooObj.

Typescript binds this by creating a local variable _this, that is bound to the this-context where the fat-arrow is declared. And in your case, this is the global scope, which is any. This is what it gets compiled into:

var _this = this;
var fooObj = {
    bar: function () {
        // TS does not error out when I access this.baz
        console.log(_this.baz);
    }
};

This is how it looks like within a class:

class Bar
{
    private var = 23;
    public makeSound = () => console.log(this.var) 
}

// Compiles into:

var Bar = (function () {
    function Bar() {
        var _this = this;
        this.var = 23;
        this.makeSound = function () { return console.log(_this.var); };
    }
    return Bar;
}());
Alex
  • 14,104
  • 11
  • 54
  • 77