Some of this is a consequence of how typescript works - it carries any structural constraints it can find forward in an advisory capacity, because it is somewhat decoupled from the quite-dynamic runtime behavior of the javascript engine.
It isn't even block-based scoping in the flow analysis above - if in your block there was the code foo = 1; the typescript engine would then expect that foo will behave like a Number at runtime.
I haven't dived in deep enough, but I suspect foo could even have different structural type information within the same expression, e.g. a ternary (typeof foo === 'string') ? something(foo) : somethingelse(foo)
It isn't even block-based scoping in the flow analysis above - if in your block there was the code foo = 1; the typescript engine would then expect that foo will behave like a Number at runtime.
I haven't dived in deep enough, but I suspect foo could even have different structural type information within the same expression, e.g. a ternary (typeof foo === 'string') ? something(foo) : somethingelse(foo)