How does TypeScript infer the type of `this`?

How does TypeScript infer the type of `this`?



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


this


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.


this


f()


this: this


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.


this


A


this


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.


f1()


f


A



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:


this


f()


this: Any


this: this


f


this: this


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?


this






is this a bug or a design feature? it's designed to work the same as javascript

– Jaromanda X
Sep 9 '18 at 3:42


is this a bug or a design feature?






@JaromandaX Thanks for your tips. I understand that this is determined by the context at call-site dynamically, in some order of precedence, as illustrated in quite some articles. But I want to know how does TypeScript infer the type of this statically.

– Ben
Sep 9 '18 at 3:46



this


this






Sorry, I get what you're asking now ... because typescript is typed you want to know how typescript knows what type this is at any given moment

– Jaromanda X
Sep 9 '18 at 3:47


this






@JaromandaX Yes, that's exactly what I want to know. Because in the example I gave, the behavior is counter-intuitive to me.

– Ben
Sep 9 '18 at 3:57






I'll add that this suggestion would give a compile error on let f1 = (new A).f.

– Matt McCutchen
Sep 9 '18 at 22:22


let f1 = (new A).f




2 Answers
2



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.


this



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 (i.e., without a this).


this


any


A


f1()


this



Thanks for contributing an answer to Stack Overflow!



But avoid



To learn more, see our tips on writing great answers.



Required, but never shown



Required, but never shown




By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

Edmonton

Crossroads (UK TV series)