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

Inference fails for return-type of intersection between class and generic type #5456

Closed
fongandrew opened this issue Oct 29, 2015 · 4 comments
Labels
Committed The team has roadmapped this issue Fixed A PR has been merged for this issue Suggestion An idea for TypeScript

Comments

@fongandrew
Copy link

When a generic type is used in an intersection type passed to a function, TS fails to infer that generic type.

Example:

interface Man {
    walks: boolean;
}

interface Bear {
    roars: boolean;
}

interface Pig {
    oinks: boolean;
}

declare function pigify<T>(y: T & Bear): T & Pig;
declare var mbp: Man & Bear;

pigify(mbp).oinks; // OK, mbp is treated as Pig
pigify(mbp).walks; // ERROR, mbp not recognized as Man

Playground: http://www.typescriptlang.org/Playground#src=interface%20Man%20%7B%0D%0A%09walks%3A%20boolean%3B%0D%0A%7D%0D%0A%0D%0Ainterface%20Bear%20%7B%0D%0A%09roars%3A%20boolean%3B%0D%0A%7D%0D%0A%0D%0Ainterface%20Pig%20%7B%0D%0A%09oinks%3A%20boolean%3B%0D%0A%7D%0D%0A%0D%0Adeclare%20function%20pigify%3CT%3E(y%3A%20T%20%26%20Bear)%3A%20T%20%26%20Pig%3B%0D%0Adeclare%20var%20mbp%3A%20Man%20%26%20Bear%3B%0D%0A%0D%0Apigify(mbp).oinks%3B%20%2F%2F%20OK%2C%20mbp%20is%20treated%20as%20Pig%0D%0Apigify(mbp).walks%3B%20%2F%2F%20Not%20OK%2C%20mbp%20not%20recognized%20as%20Man%0D%0A

This seems like the inverse of #2211. Unlike union types however, the use of an intersection type in the param should provide enough information to make the required inference.

That is, if I pass a value of type Man & Bear to a function expecting T & Bear, then T should either be Man or Man & Bear, either of which would be enough to infer that T has all of the properties expected of Man. Instead, TS seems to be inferring T to be of type {}.

Am I missing something here?

@DanielRosenwasser
Copy link
Member

Looks like #1011 is the most related issue. I think we could feasibly do this given that we've been able to do the same for union types.

@mhegazy mhegazy added Suggestion An idea for TypeScript In Discussion Not yet reached consensus labels Oct 30, 2015
@HerringtonDarkholme
Copy link
Contributor

A similar question. What about type parameter used in union type, in the position of argument?
I encounter this when trying to mock nullable type in TS. Example:

var maybeNumber: number | void = 123
function isPresent<T>(a: T | void): a is T {/*...*/}
if (isPresent(maybeNumber)) {
  maybeNumber // type is number | void here
}

TS resolves the type parameter T to number | void. It is arguable that resolving T to number is more intuitive.

And the following code works. I guess primary inference does conflict and TS fallbacks to secondary inference.

interface A {a: number}
interface B {b: number}

function isA<T extends A>(ab: T | B): ab is T {
  return true
}

var ab: A | B = {a: 1}

if (isA(ab)) {
  ab.a  // A | B is narrowed down to A
}

So what behavior does, or will, TS spec require implementation to adhere?

@sandersn
Copy link
Member

@HerringtonDarkholme #4212 is exactly what you're trying to do with isPresent.

@ahejlsberg
Copy link
Member

Now fixed by #5738.

@RyanCavanaugh RyanCavanaugh added Fixed A PR has been merged for this issue Committed The team has roadmapped this issue and removed In Discussion Not yet reached consensus labels Nov 24, 2015
@mhegazy mhegazy added this to the TypeScript 1.8 milestone Nov 24, 2015
@microsoft microsoft locked and limited conversation to collaborators Jun 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Committed The team has roadmapped this issue Fixed A PR has been merged for this issue Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

7 participants