Skip to content

Incorrect ts(18048) (possibly 'undefined' error) after optional chaining with const #53872

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

Closed
tsoestini opened this issue Apr 17, 2023 · 6 comments
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed

Comments

@tsoestini
Copy link

Bug Report

🔎 Search Terms

ts(18048)
is possibly 'undefined'.
optional chaining

🕗 Version & Regression Information

Verified bugged in 4.9.5 through 5.0.4 and the most recent Nightly as of this posting.

(The same code throws a different ts error earlier than 4.9.5.)

⏯ Playground Link

Playground link with relevant code

💻 Code

interface Foo {
    foo: {
        a: string;
        b: string;
    };
    bar: string;
}

export default function getBar(obj: Foo | undefined): string {
    const foo = obj?.foo;
    const a = foo?.a;
    if (!a) {
        throw new Error("Invalid args");
    }

    return obj.bar; // <--- obj is possible undefined here according to tsc even though it can never really be
}

🙁 Actual behavior

'obj' is possibly 'undefined'.(18048) at the final return line for 'obj'

🙂 Expected behavior

No typescript error should be shown here, because 'obj' can never be undefined since 'foo' and 'a' would then also be undefined so the code would never reach the final return.

@RyanCavanaugh RyanCavanaugh added the Design Limitation Constraints of the existing architecture prevent this from being fixed label Apr 17, 2023
@RyanCavanaugh
Copy link
Member

Narrowing only occurs based on expressions involving the variable in question (i.e. it's not a constraint-solving system). Since a isn't obj, the if (!a) { block doesn't have any effect here.

@tsoestini
Copy link
Author

If you change if (!a) to if (!foo), though, then it doesn't raise the objection, but foo is also not obj?
So it must have some minimal constaint-solving?

@RyanCavanaugh
Copy link
Member

True, there is one level of back-propagation on optional chains

@Hazmi35
Copy link

Hazmi35 commented Jun 20, 2023

Not sure if this is related or not. TypeScript 5.1.3. Found this issue when working on Maps with class that has a function as values, tried playground and got it reproduced.

Playground Link

class Hello extends Map<string, World> {
    doStuff(key: string) {
        const value = this.get(key);

        const one = value?.doStuffOne();
        if (!one) return undefined;

        value.doStuffTwo(); // <-- ts(18048) 'value' is possibly undefined.

        if (one) {
            value.doStuffTwo();  // <-- ts(18048) 'value' is possibly undefined.
        }

    }
}

class World {
    doStuffOne() {
        return true;
    }

    doStuffTwo() {
        return true;
    }
}

I'm sure that value won't be undefined after the guard clause, but tsc reports it possibly can, but not on this code:

Playground Link

class Hello extends Map<string, World> {
    doStuff(key: string) {
        const value = this.get(key);

        if(value?.doStuffOne()) value.doStuffTwo();
    }
}

class World {
    doStuffOne() {
        return true;
    }

    doStuffTwo() {
        return true;
    }
}

@birgersp
Copy link

birgersp commented Oct 27, 2023

Just wanted to chime in an another example that would perhaps illustrate the problem an an even more obvious manner:

function foobar(x: number | undefined) {
	throw new Error()
	if (x != undefined) {
		return x + 1 // <-- Compiler error TS18048: 'x' is possibly 'undefined'. False positive error.
	}
}

Playground link

I would suggest that the title of this issue could be changed to:

Type narrowing disrupted by preceding "throw" statement (TS18048)

@RyanCavanaugh
Copy link
Member

@birgersp see #26914

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed
Projects
None yet
Development

No branches or pull requests

4 participants