<p dir="auto">This may be a duplicate of <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="136289924" data-permission-text="Title is private" data-url="https://github.com/microsoft/TypeScript/issues/7234" data-hovercard-type="issue" data-hovercard-url="/microsoft/TypeScript/issues/7234/hovercard" href="https://github.com/microsoft/TypeScript/issues/7234">#7234</a> and/or <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="94344571" data-permission-text="Title is private" data-url="https://github.com/microsoft/TypeScript/issues/3812" data-hovercard-type="issue" data-hovercard-url="/microsoft/TypeScript/issues/3812/hovercard" href="https://github.com/microsoft/TypeScript/issues/3812">#3812</a>, but I don't know enough about the internals of TypeScript to know for sure. Let's say I have the following:</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="interface MyInfo&lt;T&gt; {
   data: T;
}

class Foo {
   x: number;
} 

let fooInfos: MyInfo&lt;Foo&gt;[];
let objectInfos: MyInfo&lt;Object&gt;[];

for (let info of objectInfos) {
   if (info.data instanceof Foo) {
       fooInfos.push(info); // should infer that info is MyInfo&lt;Foo&gt;, but it doesn't
   }
} "><pre class="notranslate"><span class="pl-k">interface</span> <span class="pl-smi">MyInfo</span><span class="pl-c1">&lt;</span><span class="pl-smi">T</span><span class="pl-c1">&gt;</span> <span class="pl-kos">{</span>
   <span class="pl-c1">data</span>: <span class="pl-smi">T</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span>

<span class="pl-k">class</span> <span class="pl-smi">Foo</span> <span class="pl-kos">{</span>
   <span class="pl-c1">x</span>: <span class="pl-smi">number</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span> 

<span class="pl-k">let</span> <span class="pl-s1">fooInfos</span>: <span class="pl-smi">MyInfo</span><span class="pl-kos">&lt;</span><span class="pl-smi">Foo</span><span class="pl-kos">&gt;</span><span class="pl-kos">[</span><span class="pl-kos">]</span><span class="pl-kos">;</span>
<span class="pl-k">let</span> <span class="pl-s1">objectInfos</span>: <span class="pl-smi">MyInfo</span><span class="pl-kos">&lt;</span><span class="pl-smi">Object</span><span class="pl-kos">&gt;</span><span class="pl-kos">[</span><span class="pl-kos">]</span><span class="pl-kos">;</span>

<span class="pl-k">for</span> <span class="pl-kos">(</span><span class="pl-k">let</span> <span class="pl-s1">info</span> <span class="pl-k">of</span> <span class="pl-s1">objectInfos</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
   <span class="pl-k">if</span> <span class="pl-kos">(</span><span class="pl-s1">info</span><span class="pl-kos">.</span><span class="pl-c1">data</span> <span class="pl-k">instanceof</span> <span class="pl-smi">Foo</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
       <span class="pl-s1">fooInfos</span><span class="pl-kos">.</span><span class="pl-en">push</span><span class="pl-kos">(</span><span class="pl-s1">info</span><span class="pl-kos">)</span><span class="pl-kos">;</span> <span class="pl-c">// should infer that info is MyInfo&lt;Foo&gt;, but it doesn't</span>
   <span class="pl-kos">}</span>
<span class="pl-kos">}</span> </pre></div>
<p dir="auto">In this case, the compiler still thinks <code class="notranslate">info</code> is of type <code class="notranslate">MyInfo&lt;Object&gt;</code> instead of <code class="notranslate">MyInfo&lt;Foo&gt;</code>, whereas I would expect it to be able to properly infer the type.</p>
<p dir="auto">I just found out that property access expressions doesn't work on type predicate functions and <code class="notranslate">instanceof</code> type guards.</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="
class A {
    propA: number;
}

class B {
    propB: number;
}
class C {
    propC: A;
}

declare function isA(p1: any): p1 is D;

interface D {
    a: A | B
    b: A | C;
}

let d: D;
if (isA(d.b)) {
    d.b.propA; //error
}

function foo(d: D) {
    if (d.b instanceof A) {
        d.b.propA // error
    }
}"><pre class="notranslate"><span class="pl-k">class</span> <span class="pl-smi">A</span> <span class="pl-kos">{</span>
    <span class="pl-c1">propA</span>: <span class="pl-smi">number</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span>

<span class="pl-k">class</span> <span class="pl-smi">B</span> <span class="pl-kos">{</span>
    <span class="pl-c1">propB</span>: <span class="pl-smi">number</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span>
<span class="pl-k">class</span> <span class="pl-smi">C</span> <span class="pl-kos">{</span>
    <span class="pl-c1">propC</span>: <span class="pl-smi">A</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span>

<span class="pl-k">declare</span> <span class="pl-k">function</span> <span class="pl-s1">isA</span><span class="pl-kos">(</span><span class="pl-s1">p1</span>: <span class="pl-smi">any</span><span class="pl-kos">)</span>: <span class="pl-s1">p1</span> is <span class="pl-smi">D</span><span class="pl-kos">;</span>

<span class="pl-k">interface</span> <span class="pl-smi">D</span> <span class="pl-kos">{</span>
    <span class="pl-c1">a</span>: <span class="pl-smi">A</span> <span class="pl-c1">|</span> <span class="pl-smi">B</span>
    <span class="pl-c1">b</span>: <span class="pl-smi">A</span> <span class="pl-c1">|</span> <span class="pl-smi">C</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span>

<span class="pl-k">let</span> <span class="pl-s1">d</span>: <span class="pl-smi">D</span><span class="pl-kos">;</span>
<span class="pl-k">if</span> <span class="pl-kos">(</span><span class="pl-en">isA</span><span class="pl-kos">(</span><span class="pl-s1">d</span><span class="pl-kos">.</span><span class="pl-c1">b</span><span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-s1">d</span><span class="pl-kos">.</span><span class="pl-c1">b</span><span class="pl-kos">.</span><span class="pl-c1">propA</span><span class="pl-kos">;</span> <span class="pl-c">//error</span>
<span class="pl-kos">}</span>

<span class="pl-k">function</span> <span class="pl-en">foo</span><span class="pl-kos">(</span><span class="pl-s1">d</span>: <span class="pl-smi">D</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-k">if</span> <span class="pl-kos">(</span><span class="pl-s1">d</span><span class="pl-kos">.</span><span class="pl-c1">b</span> <span class="pl-k">instanceof</span> <span class="pl-smi">A</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
        <span class="pl-s1">d</span><span class="pl-kos">.</span><span class="pl-c1">b</span><span class="pl-kos">.</span><span class="pl-c1">propA</span> <span class="pl-c">// error</span>
    <span class="pl-kos">}</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">I'm not sure if there is an easy fix on this problem. We are provided just a symbol when narrowing. That symbol represent the left most expression and then we walk up the if statement. There is no easy way of controlling symbol by symbol on each namespace in a property access expression in the if-statement-body. Because there is no info about the property access expression provided in <code class="notranslate">getTypeOfSymbolAtLocation(symbol: Symbol, node: Node)</code>.</p>
<p dir="auto">I also found that type assertion expressions are also not working in type predicate functions. But I will land a fix on that.</p>
<div class="highlight highlight-source-ts notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="if (isA(&lt;A&gt;union)) {
    a = union;
}
if (isA(union as A)) {
    a = union;
}"><pre class="notranslate"><span class="pl-k">if</span> <span class="pl-kos">(</span><span class="pl-en">isA</span><span class="pl-kos">(</span><span class="pl-kos">&lt;</span><span class="pl-smi">A</span><span class="pl-kos">&gt;</span><span class="pl-s1">union</span><span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-s1">a</span> <span class="pl-c1">=</span> <span class="pl-s1">union</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span>
<span class="pl-k">if</span> <span class="pl-kos">(</span><span class="pl-en">isA</span><span class="pl-kos">(</span><span class="pl-s1">union</span> <span class="pl-k">as</span> <span class="pl-smi">A</span><span class="pl-kos">)</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-s1">a</span> <span class="pl-c1">=</span> <span class="pl-s1">union</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span></pre></div>