Skip to content

strictNullChecks: false positive with switch in for loop #27239

Closed
@AlCalzone

Description

@AlCalzone

TypeScript Version: 3.1.0-dev.20180920

Search Terms: strictNullChecks

Code
This might seem weird, but is based on actual real-world code.

declare function baz(): Promise<true | "a" | "b" | "c" | Error>;

async function foo() {
    let bar: "x" | Error;
    for (let i = 0; i < 3; i++) {
        const test = await baz();
        switch (test) {
            case true: return;
            case "a": throw new Error("a");
            case "b": {
                bar = "x";
                continue;
            }
            default: {
                if (test instanceof Error) {
                    bar = new Error("foo");
                    continue;
                } else {
                    throw new Error("c");
                }
            }
        }
    }
    // false positive: bar is used before being assigned
    if (bar === "x") {

    } else {
        bar.message = "something";
    }
}

Expected behavior:
No error after the for loop. The only way to get there is if bar has the value "x" or is an instance of Error. If baz resolves to true, the function returns, "b" sets bar to "x", and "a" and everything that is not an Error (including "c" throw, and an Error sets it to an Error.

Actual behavior:
Variable "bar" is used before being assigned.

Playground Link: https://www.typescriptlang.org/play/#src=declare%20function%20baz()%3A%20Promise%3Ctrue%20%7C%20%22a%22%20%7C%20%22b%22%20%7C%20%22c%22%20%7C%20Error%3E%3B%0D%0A%0D%0Aasync%20function%20foo()%20%7B%0D%0A%20%20%20%20let%20bar%3A%20%22x%22%20%7C%20Error%3B%0D%0A%20%20%20%20for%20(let%20i%20%3D%200%3B%20i%20%3C%203%3B%20i%2B%2B)%20%7B%0D%0A%20%20%20%20%20%20%20%20const%20test%20%3D%20await%20baz()%3B%0D%0A%20%20%20%20%20%20%20%20switch%20(test)%20%7B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20case%20true%3A%20return%3B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20case%20%22a%22%3A%20throw%20new%20Error(%22a%22)%3B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20case%20%22b%22%3A%20%7B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20bar%20%3D%20%22x%22%3B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20continue%3B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20default%3A%20%7B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(test%20instanceof%20Error)%20%7B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20bar%20%3D%20new%20Error(%22foo%22)%3B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20continue%3B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20%7B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20throw%20new%20Error(%22c%22)%3B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0D%0A%20%20%20%20%20%20%20%20%7D%0D%0A%20%20%20%20%7D%0D%0A%20%20%20%20if%20(bar%20%3D%3D%3D%20%22x%22)%20%7B%0D%0A%20%20%20%20%20%20%20%20%0D%0A%20%20%20%20%7D%20else%20%7B%0D%0A%20%20%20%20%20%20%20%20bar.message%20%3D%20%22something%22%3B%0D%0A%20%20%20%20%7D%0D%0A%7D

Related Issues: #24091

Metadata

Metadata

Assignees

No one assigned

    Labels

    Working as IntendedThe behavior described is the intended behavior; this is not a bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions