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

Breaking Change: Unexpected narrowing to never when "in" guard used on intersection #38162

Closed
RyanCavanaugh opened this issue Apr 24, 2020 · 1 comment · Fixed by #39637
Closed
Assignees
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue

Comments

@RyanCavanaugh
Copy link
Member

TypeScript Version: 3.8.3 vs nightly

Search Terms: intersection in operator

Code

type MaybeFoo = {
    bar: string;
    foo?: number;
};
type AlwaysFoo = {
    foo: number | undefined;
    always: string;
};

declare const f: AlwaysFoo & MaybeFoo;
if ("foo" in f) {
    f.bar;
} else {
    // 3.8.3: f: AlwaysFoo & MaybeFoo
    // 3.9: 'f' is 'never'
    f.bar;
}

Expected behavior: Well...

This is probably technically the correct behavior. However, for the specific case of window, this is problematic. There are globals like ontouchstart which are declared as being var ontouchstart: whatever | undefined in the global scope; these get intersected with the global Window type, and because we believe "variables can't be optional", we start narrowing to never in the else branch here.

It's unclear what we should do differently here, but this caused a break in a few different places in real world code where people are doing feature detection. We're incorrectly telling people that e.g. ontouchstart is always present, even though you would get an error to unconditionally invoke it (because it is indeed possibly-undefined).

Since there's still no "optional var" and still no "missing vs undefined", we should maybe treat properties that include undefined as "possibly not in" for the purposes of narrowing.

Actual behavior: Described

Playground Link: Link

Related Issues: Possible root cause: #37106

@RyanCavanaugh RyanCavanaugh added the Needs Investigation This issue needs a team member to investigate its status. label Apr 24, 2020
@RyanCavanaugh RyanCavanaugh self-assigned this Apr 24, 2020
@RyanCavanaugh RyanCavanaugh added Bug A bug in TypeScript and removed Needs Investigation This issue needs a team member to investigate its status. labels Apr 24, 2020
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 4.0 milestone Apr 24, 2020
@sandersn
Copy link
Member

See discussion at the fix; briefly, the minimal fix for this bug is the right one because the real fix for the whole feature is to introduce the missing type.

@sandersn sandersn added the Fix Available A PR has been opened for this issue label Jul 17, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants