title: Narrow container of generic by generic
body: <p>If I have a generic container like this</p>
  
  <pre><code>export interface A {
   type: 'A',
   value: string
  }
  
  export interface B {
   type: 'B',
   value: number
  }
  
  export interface Container&lt;T&gt; {
    data: T
  }
  
  export type ContainerOfAB = Container&lt;A | B&gt;
  </code></pre>
  
  <p>Is it possible to narrow the type of a <code>ContainerOfAB</code> by the value of its data object? For example:</p>
  
  <pre><code>export interface A {
   type: 'A',
   value: string
  }
  
  export interface B {
   type: 'B',
   value: number
  }
  
  export interface Container&lt;T&gt; {
    data: T
  }
  
  export type ContainerOfAB = Container&lt;A | B&gt;
  
  export function detect(item: ContainerOfAB) {
    switch(item.data.type) {
      case 'A':
        takesGenericA(item) // fails
        break;
       case 'B':
        takesGenericB(item) // fails
        break;
    }
  }
  
  function takesGenericA(e: Container&lt;A&gt;) {
  
  }
  
  function takesGenericB(e: Container&lt;B&gt;) {
  
  }
  </code></pre>
  
  <p>It seems that its not able to narrow the container's inner value enough to pass to another method, even though the switch does work?</p>
  
  <p>This example gives the following error to either of the invocations of the narrowed type</p>
  
  <pre><code>Argument of type 'ContainerOfAB' is not assignable to parameter of type 'Container&lt;B&gt;'.
    Type 'A | B' is not assignable to type 'B'.
      Type 'A' is not assignable to type 'B'.
        Types of property 'type' are incompatible.
          Type '"A"' is not assignable to type '"B"'.(2345)
  </code></pre>
  
  <p>Here is a <a href="https://www.typescriptlang.org/play/#code/KYDwDg9gTgLgBASwHY2FAZgQwMbDgQTgG8BYAKDhgE8xgAuOAcn0YBpy4A3TAGwFd6cAM4woyAObkAvuXKhIsRCjRZccAELEO1Wg0bq2Hbv0FI+AWwBGaabLLzo8ZKgw48AYQgpMyNAB4AFQA+LQo4ABNMGEwGANsyOXBHShoPL2jfKAB5dHxNAF44T29Mv0IAHw0guwdFdD4kbBgELwjgVCaACgRUcwZijKQ0HLyASlC4YQB3HuwAC27egDpI6KWdYHHSMMnsTCE8ZkY6Dkmz6IBrYCEAcWAhsWx8ReBzUdOzuEsoYEwLgG4Prt9ocDCcdp9KH9rncHghsOoXm8gZ9vr8AacZGQseR6o1mq1LjD7mh4c9BAMfA8ykEtnYcWQ8U0WkgoVdbiTHoiKekqf51LTQtIgA" rel="nofollow noreferrer">playground</a></p>