Skip to content

Conditional type based on enum is not respected when branches include class instances with different constructor signatures #35371

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
cyorobert opened this issue Nov 26, 2019 · 2 comments
Labels
Duplicate An existing issue was already created

Comments

@cyorobert
Copy link

TypeScript Version: 3.7.x-dev.201xxxxx

Reproduced Issue with TS Nightly: http://www.typescriptlang.org/play/?ts=3.8.0-dev.20191125#code/KYOwrgtgBAYg9nAJlA3gKCpgygQQHIAiA6gJIDCAEgDQbYDyAqgApoC+aAliAC7ABOAMwCGAY2BQAssCEAbJn2AAHADzwkAFQCei4AD5UtKBCEBrYGsQAKAJQAuWAkRadbNCJlCAzp6hYhIRAB3DhEACwNMTBE4EE9uPjARbjg+S0U+DgA3IV4oBSFEGJlNKC4AcwVEDlBuT3s4jJAygG0AXWtUKHZ2dy8fLDgwRQiomIbE5NT0rJzxfMKQYtKmyuqeOqgG8raOlC7XXu9ffyCQ0Kx+TJDxDghFGWAIGp8pWXklZT8A4LD9dEioNFYvEJik0hlsrl5kUSgIEPZwBAAEb8XbsAHGMwWGz2L6nMIjAGYBTcMB8EBQEDAQLHb5nSzNADkoSEEEZVCgjLCwGAnmAjPaAG5DPsDh4jgMhhc+FcxKU7g8nutJNI5AoVJLFH8RUDxkkwdNIXNpAslnC4PV4uU0SLMeZHDjfINhv8icTgKTyZTqU6hgzGcljMl2ZyRHxBskQALrMKAd00GhuNpxHghHxw4FgIgLMp1FBgAAPXgBHwWfQAXhFecLxcQpccADosIwmFAAPy+xTS2XiWxV-NF0B1hxIJv4YjkCjt2n486Xa5QPsAqmZfgJgD066gJB8HG4UEUcG8HCRDygyUpaYz59CHB8SZ0UBSmxBSTJ4m4t93FKEUECQhKT8cigIRMjgDhhzAEAODGNs0AEKCkhgikyg9V41Q+atBxLEdEF0SxzUQex1DsKBU3TOBM2zRxc21AFPGCbgCQIxxdhFAERC8cQLCbFslzdIkSTJCkqRpTVu2uSxGULVl7nEOABCgbI+E0cpATGV9Jk2DgyhAHJ30Zax2MiTi+VwsdCFISh+IEyIhK9USZx+OcZUkgBGAAmABmIy41cNAHn3c0oHLKBUO4dD3kUSweNwSzJyMoA

Search Terms:

  • typescript conditional type class instances
  • typescript conditional type with different constructors signatures
  • typescript conditional type with enum example

Code

// A *self-contained* demonstration of the problem follows...
// Test this by running `tsc` on the command-line, rather than through another build tool such as Gulp, Webpack, etc.
enum Food {
   SANDWICH,
   SOUP
}
interface MealPrep<FoodType> {
   makeFood(): FoodType
}
class Sandwich {
    constructor(private readonly ingredients: string[]) { }
}
class Soup {
   constructor(private readonly ingredients: string[]) { }
}
class SandwichService implements MealPrep<Sandwich> {
    constructor(private readonly foo: number) {}
    makeFood(): Sandwich {
        return new Sandwich(['ham', 'cheese']);
    }

}
class SoupService implements MealPrep<Soup> {
    constructor(private readonly foo: string) {}
    makeFood(): Soup {
        return new Soup(['tomato', 'crouton']);
    }
}

type NarrowedFood<T extends Food> =
    T extends Food.SOUP ? SoupService :
    T extends Food.SANDWICH ? SandwichService :
    never

// Is it possible to narrow this type or structure this in a way that avoids unions?
function getMealPrep<T extends Food>(food: T): NarrowedFood<T> {
    switch (food) {
        case Food.SOUP:
            return new SoupService('example of varying constructor signature')
        case Food.SANDWICH:
            return new SandwichService(123)
    }
}

const example = getMealPrep(Food.SANDWICH)
const sandwich = example.makeFood() // does correctly resolve to Sandwich

I would like to use an enum to construct one of a fixed set of types and then use a conditional type to narrow the return value to a single type that's relevant for a given branch of an enum.

In the example above, if I supply getMealPrep(Food.SOUP) I would like the inference engine to understand that I will get back a SoupService instance. This works as expected when SoupService and SandwichService have the same constructor signatures, however, when the signatures of SoupService and SandwichService differ I get the error Returned expression type SoupService is not assignable to type NarrowedFood<T>.

Expected behavior:
I would expect not to receive an error in getMealPrep when SoupService and SandwichService have different constructor type signatures.

Actual behavior:

Screen Shot 2019-11-26 at 3 31 35 PM

Playground Link:

http://www.typescriptlang.org/play/?ts=3.8.0-dev.20191125#code/KYOwrgtgBAYg9nAJlA3gKCpgygQQHIAiA6gJIDCAEgDQbYDyAqgApoC+aAliAC7ABOAMwCGAY2BQAssCEAbJn2AAHADzwkAFQCei4AD5UtKBCEBrYGsQAKAJQAuWAkRadbNCJlCAzp6hYhIRAB3DhEACwNMTBE4EE9uPjARbjg+S0U+DgA3IV4oBSFEGJlNKC4AcwVEDlBuT3s4jJAygG0AXWtUKHZ2dy8fLDgwRQiomIbE5NT0rJzxfMKQYtKmyuqeOqgG8raOlC7XXu9ffyCQ0Kx+TJDxDghFGWAIGp8pWXklZT8A4LD9dEioNFYvEJik0hlsrl5kUSgIEPZwBAAEb8XbsAHGMwWGz2L6nMIjAGYBTcMB8EBQEDAQLHb5nSzNADkoSEEEZVCgjLCwGAnmAjPaAG5DPsDh4jgMhhc+FcxKU7g8nutJNI5AoVJLFH8RUDxkkwdNIXNpAslnC4PV4uU0SLMeZHDjfINhv8icTgKTyZTqU6hgzGcljMl2ZyRHxBskQALrMKAd00GhuNpxHghHxw4FgIgLMp1FBgAAPXgBHwWfQAXhFecLxcQpccADosIwmFAAPy+xTS2XiWxV-NF0B1hxIJv4YjkCjt2n486Xa5QPsAqmZfgJgD066gJB8HG4UEUcG8HCRDygyUpaYz59CHB8SZ0UBSmxBSTJ4m4t93FKEUECQhKT8cigIRMjgDhhzAEAODGNs0AEKCkhgikyg9V41Q+atBxLEdEF0SxzUQex1DsKBU3TOBM2zRxc21AFPGCbgCQIxxdhFAERC8cQLCbFslzdIkSTJCkqRpTVu2uSxGULVl7nEOABCgbI+E0cpATGV9Jk2DgyhAHJ30Zax2MiTi+VwsdCFISh+IEyIhK9USZx+OcZUkgBGAAmABmIy41cNAHn3c0oHLKBUO4dD3kUSweNwSzJyMoA

Related Issues:
I couldn't find any bugs that looked similar.

@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label Dec 10, 2019
@RyanCavanaugh
Copy link
Member

See #33912

@typescript-bot
Copy link
Collaborator

This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

3 participants