简体   繁体   中英

How does TypeScript infer the type of `this`?

The inference strategy of this in TypeScript is confusing to me, for example:

class A {
    s: String
    constructor() {
        this.s = "this is fine"
    }
    f() {
        console.log(this.s)
    }
}

let a = new A

a.f() // -> this is fine

let f1 = (new A).f
f1() // -> undefined

If you put the code into TypeScript Playground , and check the type of this inside f() , you can see that it's inferred to be of type this: this , which means the subtype of A .

In this situation, I think it means this is bind to A , and can't refer to the global object. Otherwise, this should be inferred to be of type this: Any .

But actually, as shown in the invocation of f1() , if the function f is invoked outside the context of A , it could still be the global object.

So in my opinion, the inferred type of this inside f() should be this: Any , not this: this . And only if the function f is defined with arrow function could it be inferred to be this: this . For example:

class A {
    s: String
    constructor() {
        this.s = "this is fine"
    }
    f = () => {
        console.log(this.s)
    }
}

let a = new A

a.f() // -> this is fine

let f1 = (new A).f
f1() // -> this is fine

So, is this a bug or a design feature? How does TypeScript infer the type of this actually?

So in my opinion, the inferred type of this inside f() should be this: any, not this: this.

well, yes. In some ways you're right. It is not 100% sure that this inside a class function is really an instance of the class. But typescript is not meant to be 100% accurate ! This is important to understand! The type guarantees don't hold in all situations. They literally can't.

Javascript is very dynamic. There is no way to just analyze all this dynamics at compile time.

So Typescript purely relies on assumptions and user provided type information. It should help you, but wont stop you when you want to shoot into your own feet.

Just never do this:

const x = foo.x;
x();

actually this has the effect that older class models then ES6 classes like the ember object model are very hard to use with typescript - the assumptions just dont hold up. And even the best typings have limitations. There are things you can do in JS you can not define in TS. Still TS can be very helpful for all other cases.

Great question. Typescript has what we call an unsound type system. (Closure Compiler and Flow also have unsound type systems.) An unsound type system means that Typescript will sometimes compute a type for an expression that is wrong; it is different from the type that the expression will take at runtime. As mentioned in the other reply, this happens because JavaScript is very dynamic, and type-system designers take a few shortcuts in order to tame the complexity.

In your particular example, even though this can indeed by any , in practice it is almost always A , so that's what Typescript chooses. However, it could potentially warn at f1() , because the method is called as a function (ie, without a this ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM