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

TypeChecker::getTypeAtLocation(Identifier) does not Return Narrowed Type Inside an Array.isArray()-Based Type Guard #8094

Closed
SlurpTheo opened this issue Apr 14, 2016 · 8 comments
Labels
API Relates to the public API for TypeScript Bug A bug in TypeScript

Comments

@SlurpTheo
Copy link

1.8.10 / next (1.9.0-dev.20160414)

Code

export function X() {
    let x: number | number[] = 0;

    if (typeof x === "number") {
        x;              // ts.createProgram(...).getTypeChecker().getTypeAtLocation(Identifier::x).getFlags() --> number
        const y = x;    // ts.createProgram(...).getTypeChecker().getTypeAtLocation(Identifier::y).getFlags() --> number
    }
    if (typeof x !== "object") {
        x;              // ts.createProgram(...).getTypeChecker().getTypeAtLocation(Identifier::x).getFlags() --> number
        const y = x;    // ts.createProgram(...).getTypeChecker().getTypeAtLocation(Identifier::y).getFlags() --> number
    }
    if (!Array.isArray(x)) {
        x;              // ts.createProgram(...).getTypeChecker().getTypeAtLocation(Identifier::x).getFlags() --> Union
        const y = x;    // ts.createProgram(...).getTypeChecker().getTypeAtLocation(Identifier::y).getFlags() --> number
    }

Behavior:
Why does TypeChecker::getTypeAtLocation(Identifier::x) correctly report number after the first (typeof x === "number") & second (typeof x !== "object") type guards, but report the (un-narrowed) Union type after the third (!Array.isArray(x)) type guard? All three block's const c is correctly typed as number. Is there something besides TypeChecker::getTypeAtLocation(Identifier) to use here?

@mhegazy
Copy link
Contributor

mhegazy commented Apr 14, 2016

how about getSymbolAtLocation(), getTypeOfSymbolAtLocation(symbol, node) ? do you see any difference?

@mhegazy mhegazy added Bug A bug in TypeScript API Relates to the public API for TypeScript labels Apr 14, 2016
@SlurpTheo
Copy link
Author

Doing getTypeOfSymbolAtLocation(getSymbolAtLocation(Identifier::x), Identifier::x) gives me the same (Union) type, yes (that also correctly reports number in the first two type guard blocks).

@SlurpTheo
Copy link
Author

SlurpTheo commented Apr 26, 2016

This appears fixed in typescript@next (1.9.0-dev.20160426) -- probably by #8010

... although, in this version of the code if you add an else to !Array.isArray(x):

export function X() {
    let x: number | number[] = 0;

    if (!Array.isArray(x)) {
        const y = x;
    } else {
        const z = x;
    }

You end up with the type of variable z being ts.TypeFlags.Anonymous...

@mhegazy
Copy link
Contributor

mhegazy commented Apr 27, 2016

i believe this should be addressed by #8324.

@SlurpTheo
Copy link
Author

OK, tried typescript@next (1.9.0-dev.20160428) and now I get number reported in both branches for TypeChecker::getTypeAtLocation(Identifier::x), but TypeChecker::getTypeAtLocation(VariableDeclaration::z) is returning ts.TypeFlags.Anonymous.

@mhegazy
Copy link
Contributor

mhegazy commented Apr 28, 2016

this is control flow analysis in action :D

let x: number | number[] = 0;

// x here can only be a number, you assigned 0 to it

if (!Array.isArray(x)) {
   // it is a number not an array alright
   const y = x;
} else {
   // it was a number, now we can only be in this branch if it is an array, but it ain't. so it is nothing.
    const z = x;
}

this should do what you expect:

let x: number | number[]; // notice, no initialization

if (!Array.isArray(x)) {
    const y = x; // number
} else {
    const z = x; // number[]
}

@mhegazy
Copy link
Contributor

mhegazy commented Apr 28, 2016

looks like this was fixed. closing.

@mhegazy mhegazy closed this as completed Apr 28, 2016
@mhegazy mhegazy added this to the TypeScript 2.0 milestone Apr 28, 2016
@SlurpTheo
Copy link
Author

@mhegazy That... is... holy!!!

I think I'm in love with this 👍

@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
API Relates to the public API for TypeScript Bug A bug in TypeScript
Projects
None yet
Development

No branches or pull requests

2 participants