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

Adding explicit type that is the same as the inferred type prevents narrowing later on #51757

Closed
winstliu opened this issue Dec 5, 2022 · 2 comments
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed

Comments

@winstliu
Copy link
Member

winstliu commented Dec 5, 2022

Bug Report

I work in a codebase that recommends adding explicit types. In this case, adding a type that is the same as the inferred type (as claimed by the hover tooltips) causes narrowing to fail for a previous maybe-null type that depends on the result that has the explicit type.

🔎 Search Terms

explicit type, narrowing

🕗 Version & Regression Information

Prior to 4.4, both explicit & inferred types would complain that obj could be null.
After 4.4 (and up to 5.0-nightly), the inferred type behaves correctly, but the explicit type still does not see that obj can no longer be null.

⏯ Playground Link

Playground link with relevant code

💻 Code

interface DeeplyNestedObject {
    deeply: {
        nested: {
            object: string;
        }
    }
}

function example(): DeeplyNestedObject | null {
    return Math.random() > 0.5 ? {
        deeply: {
            nested: {
                object: 'hi'
            }
        }
    } : null;
}

function explicit(): DeeplyNestedObject | undefined {
    const obj = example();
    // Explicit type which is the same as the inferred type
    const result: string | undefined = obj?.deeply?.nested?.object;
    if (!result) {
        return undefined;
    }

    // obj can no longer be null, as we've validated that result is truthy which is only possible if obj != null.

    // ts2322: Type 'DeeplyNestedObject | null' is not assignable to type 'DeeplyNestedObject | undefined'.
    // Type 'null' is not assignable to type 'DeeplyNestedObject | undefined'.
    return obj;
}

function inferred(): DeeplyNestedObject | undefined {
    const obj = example();
    // Inferred type
    const result = obj?.deeply?.nested?.object;
    if (!result) {
        return undefined;
    }

    return obj;
}

🙁 Actual behavior

TypeScript claims that obj can still be null, even though we've eliminated that possibility by performing some optional chaining with obj and then checking to make sure that the result was truthy.

🙂 Expected behavior

The same as the inferred example - no compiler errors.

@MartinJohns
Copy link
Contributor

This is intentional. See #44730:

Narrowing through indirect references occurs only when the conditional expression or discriminant property access is declared in a const variable declaration with no type annotation, [..]

@winstliu
Copy link
Member Author

winstliu commented Dec 5, 2022

Thanks @MartinJohns - should this be considered a feature request instead then, or "wontfix"?

@RyanCavanaugh RyanCavanaugh added the Design Limitation Constraints of the existing architecture prevent this from being fixed label Dec 5, 2022
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

3 participants