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

Reduce empty intersections to never #18210

Closed
leoasis opened this issue Sep 1, 2017 · 4 comments · Fixed by #18438
Closed

Reduce empty intersections to never #18210

leoasis opened this issue Sep 1, 2017 · 4 comments · Fixed by #18438
Assignees
Labels
Bug A bug in TypeScript Fixed A PR has been merged for this issue

Comments

@leoasis
Copy link

leoasis commented Sep 1, 2017

TypeScript Version: 2.4.0

Code

type A = {
    foo?: {
        bar?: string;
    }
}

type B = {
    foo?: {
        baz?: number
    };
}

type C = A & B;

let c: C = { foo: { bar: '123', baz: 123 } };

if (c.foo) {
    console.log(c.foo.bar); // throws error
}

Expected behavior:

This should not raise an error, as I've already checked for existance of foo in c, so the object in foo should have both bar and baz as optional with their respective types. The type should be refined because I've already checked for the existance of foo.

Actual behavior:

Typescript shows an error when trying to access either bar or baz, as each property doesn't exist in one of the combinations of the intersection type, but the combination includes foo being undefined, which I checked above.

@mhegazy
Copy link
Contributor

mhegazy commented Sep 5, 2017

The issue here is that intersection operator does not reduce empty types. e.g. in this example the type of foo in A & B is ({bar: string} | undefined) & ({baz: number} | undefined) which then distributes to: ({bar: string} & {baz: number}) | ({bar: number} & undefined) | ({bar: string} & undefined) | ({baz: number} & {bar: string}), {bar: number} & undefined and {bar: string} & undefined are empty sets (i.e. never) and should be eliminated, but that is not how intersection operator works.

I would like to keep this open for now, we have been getting this request often, and reducing these empty sets is what users expect any ways.

@mhegazy
Copy link
Contributor

mhegazy commented Sep 5, 2017

Related:

#13203
#16386
#13300

@mhegazy mhegazy changed the title Nested optionals with intersection don't play well with refinement Reduce empty intersections to never Sep 5, 2017
@mhegazy mhegazy added Suggestion An idea for TypeScript In Discussion Not yet reached consensus labels Sep 5, 2017
@leoasis
Copy link
Author

leoasis commented Sep 6, 2017

Thanks for pointing out other issues talking about this!

Yeah I think that would be a good way to solve this problem. Another one (not sure if it would be indeed different implementation-wise, or if it would require the same things to be modified), would be to improve the type refinement (i.e. changing the type after the if) so that it is smart enough to strip out the types that don't pass the condition.

I believe probably the suggestion to reduce never types is more general, and has more benefits (such as type readability), but just wanted to mention the other one in case it happens to have less impact or it is easier to implement, or just to consider it

@mhegazy
Copy link
Contributor

mhegazy commented Sep 6, 2017

Had an offline discussion about with @ahejlsberg. this is not about reduction of the intersection, but about handling null and undefined better when building the intersection type. we should remove them, build the union, then add them to the output.

@mhegazy mhegazy added Bug A bug in TypeScript and removed In Discussion Not yet reached consensus Suggestion An idea for TypeScript labels Sep 8, 2017
@mhegazy mhegazy added this to the TypeScript 2.6 milestone Sep 8, 2017
@ahejlsberg ahejlsberg assigned ahejlsberg and unassigned sandersn Sep 13, 2017
@ahejlsberg ahejlsberg added the Fixed A PR has been merged for this issue label Sep 13, 2017
@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
Bug A bug in TypeScript Fixed A PR has been merged for this issue
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants