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

Bug: null can be excluded by !== null in flow before typeof === 'object', but not excluded by predicate function. #60102

Open
LumaKernel opened this issue Sep 30, 2024 · 0 comments

Comments

@LumaKernel
Copy link

LumaKernel commented Sep 30, 2024

🔎 Search Terms

"null", "control flow", "narrowing", "narrow", "exclusion", "object", "typeof"

🕗 Version & Regression Information

Potentially, we could expect the behaviors of if (a === null) and if ((v => v !== null)(a)) (inferred as predicate since TS 5.5) should be the same, but it's actually not in specific cases.

If it's combined with typeof a === 'object' check in the same flow, first one is correctly omits the null possibility, while second one doesn't.

image

⏯ Playground Link

https://www.typescriptlang.org/play/?ts=5.6.2#code/MYewdgzgLgBAlhAcgVwDapgXhgCgG4BcMyYA1mCAO5gCUWAfDHlptmGqgNwBQA9LzEEwAegH5uoSLABmWXAEMiJclVoMYAb25D4snAhToc8mnQBOAUyjIzYHjrh6oATwAOFkLPkwAhKxgA5CAARgBWFsBQAeZWNnbaQvL2-CLiAL483BLg0DAA5nLGSmQU1HSYjFoOet6sbBwx1rb2Qo64Lu6eMN5+2EFhEVGNcS2CSdopYtwZQA

💻 Code

const isNull = (v: unknown) => v === null;
//    ^?
const f = (a: unknown) => {
    if (isNull(a)) return;
    if (typeof a !== 'object') return;
    a;
 // ^?
};


const g = (a: unknown) => {
    if (a === null) return;
    if (typeof a !== 'object') return;
    a;
 // ^?
};

🙁 Actual behavior

Last a in f is inferred as object | null.

🙂 Expected behavior

Last a in f would be inferred as object.

Additional information about the issue

Here is important to check typeof === 'object' after the check for null, because type narrowing step is formally, unknownobject | nullobject. === null alone cannot narrow anything on unknown.

If you swap the if-statements in above, you can see both is inferred as object.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant