title: Discriminating A Union of Classes
body: <p>Using Typescript 3.4 I am attempting to discriminate between a union of typescript classes based on a single readonly field (discriminator) locate on each subclass; in itself seems simple enough but I cannot seem to get it to resolve.</p>
  
  <p>Below is a link to a playground, where the createFruit method should be able to take a generic parameter to filter the next property by the discriminator. Any insights would be greatly appreciated; however, it seems to allows evaluates to never.</p>
  
  <pre><code>abstract class Fruit {
      abstract readonly fruitType: string;
  }
  
  class Banana extends Fruit {
      fruitType = 'banana';
      length = 2;
      color = 'yellow';
  }
  
  class Pear extends Fruit {
      fruitType = 'pear';
      roundness = 'very round';
  }
  
  class Apple extends Fruit {
      fruitType = 'apple';
      fallOfMan = true;
      hasWorms = true;
  }
  
  type KnownFruits = Banana | Pear | Apple;
  
  type FruitTypes = KnownFruits['fruitType'];
  
  type FruitDiscriminator&lt;T extends FruitTypes&gt; = Extract&lt;KnownFruits, { fruitType: T }&gt;;
  
  let createFruit = &lt;T extends FruitTypes&gt;(fruitType: T, props: FruitDiscriminator&lt;T&gt;) =&gt; { }
  
  createFruit('pear', {} ) // Argument of type '{}' is not assignable to parameter of type 'never'.
  </code></pre>
  
  <p><a href="https://www.typescriptlang.org/play/#src=abstract%20class%20Fruit%20%7B%0D%0A%20%20%20%20abstract%20readonly%20fruitType%3A%20string%3B%0D%0A%7D%0D%0A%0D%0Aclass%20Banana%20extends%20Fruit%20%7B%0D%0A%20%20%20%20fruitType%20%3D%20&#39;banana&#39;%3B%0D%0A%20%20%20%20length%20%3D%202%3B%0D%0A%20%20%20%20color%20%3D%20&#39;yellow&#39;%3B%0D%0A%7D%0D%0A%0D%0Aclass%20Pear%20extends%20Fruit%20%7B%0D%0A%20%20%20%20fruitType%20%3D%20&#39;pear&#39;%3B%0D%0A%20%20%20%20roundness%20%3D%20&#39;very%20round&#39;%3B%0D%0A%7D%0D%0A%0D%0Aclass%20Apple%20extends%20Fruit%20%7B%0D%0A%20%20%20%20fruitType%20%3D%20&#39;apple&#39;%3B%0D%0A%20%20%20%20fallOfMan%20%3D%20true%3B%0D%0A%20%20%20%20hasWorms%20%3D%20true%3B%0D%0A%7D%0D%0A%0D%0Atype%20KnownFruits%20%3D%20Banana%20%7C%20Pear%20%7C%20Apple%3B%0D%0A%0D%0Atype%20FruitTypes%20%3D%20KnownFruits%5B&#39;fruitType&#39;%5D%3B%0D%0A%0D%0Atype%20FruitDiscriminator%3CT%20extends%20FruitTypes%3E%20%3D%20Extract%3CKnownFruits%2C%20%7B%20fruitType%3A%20T%20%7D%3E%3B%0D%0A%0D%0Alet%20createFruit%20%3D%20%3CT%20extends%20FruitTypes%3E(fruitType%3A%20T%2C%20props%3A%20FruitDiscriminator%3CT%3E)%20%3D%3E%20%7B%20%7D%0D%0A%0D%0AcreateFruit(&#39;pear&#39;%2C%20%7B%7D%20)" rel="nofollow noreferrer">TS Playground</a></p>