Skip to content
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

Generic type constraint works on interface, but not function within interface #17039

Closed
WhitWaldo opened this issue Jul 9, 2017 · 2 comments
Closed
Labels
Question An issue which isn't directly actionable in code

Comments

@WhitWaldo
Copy link

TypeScript Version: 2.4.1

Code:

class Woof {
    constructor(private a: boolean = true) {}
}

class Meow {
    constructor(private b: string = "abc") {} 
}

class Dog implements Animal  {
    doSomething(sound: Woof): Woof {
        return new Woof();
    }
}

class Cat implements Animal {
    doSomething(sound: Meow): Meow {
        return new Meow();
    }
}

interface Animal {
    doSomething: <T extends Woof | Meow>(input: T) => T; 
}

Expected behavior:
Should compile without error, allowing me to specify that doSomething can accept a type of only Woof or Meow as a parameter and should output that type as the return value.

Actual behavior:
Yields the following error from compiler (for Dog and a similar error for Cat):

Class 'Dog' incorrectly implements interface 'Animal'.
Types of property 'doSomething' are incompatible.
Type '(sound: Woof) => Woof' is not assignable to a type '(input: T) => T'.
Types of parameters 'sound' and 'sound' are incompatible.
Type 'T' is not assignable to type 'Woof'.
Type 'Woof | Meow' is not assignable to type 'Woof'.
Type 'Meow' is not assignable to type 'Woof'.
Property 'a' is missing in type 'Meow'

Workaround:
Moving the generic constraint to the Animal interface and off the function itself resolves the issue as in the following:

class Woof {
  constructor(private a: boolean = true) { }
}

class Meow {
  constructor(private b: string = "abc") { }
}

class Dog implements Animal<Woof> {
  doSomething(sound: Woof): Woof {
    return new Woof();
  }
}

class Cat implements Animal<Meow> {
  doSomething(sound: Meow): Meow {
    return new Meow();
  }
}

interface Animal<T extends Meow | Woof> {
  doSomething(input: T): T;
}

Additional Notes
Variations of problem code not working at this SO question

Also, problem code works fine in TypeScript Playground, just produces errors when compiled locally (and in VSCode).

@WhitWaldo WhitWaldo changed the title Inferring generic type constraint works on interface, but not function within interface Generic type constraint works on interface, but not function within interface Jul 9, 2017
@ghost
Copy link

ghost commented Jul 10, 2017

When you write doSomething: <T extends Woof | Meow>(input: T) => T; , it specifies that doSomething must be a function generic in T. So if you have a: Animal you can call a.doSomething<Woof>(woof) safely. But if a was a cat that would not be safe.
#16368 started checking generic signatures, so we will now give you errors in this case.

In contrast, when you declare Cat implements Animal<Meow>, it's better, because you can' just have an a: Animal, you would have to specify the T.

Unfortunately, due to function bivariance, we would allow you to pass let a: Animal<Meow | Wolf> = new Cat(). There are many issues about that, such as #10717, #12498, #9825, #16735, #14973.

@mhegazy mhegazy added the Needs Investigation This issue needs a team member to investigate its status. label Aug 29, 2017
@mhegazy mhegazy added Question An issue which isn't directly actionable in code and removed Needs Investigation This issue needs a team member to investigate its status. labels Nov 21, 2017
@typescript-bot
Copy link
Collaborator

Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.

@microsoft microsoft locked and limited conversation to collaborators Jun 14, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

3 participants