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

JSDoc type is not narrowing a union (but typescript does) #61339

Open
xPaw opened this issue Mar 3, 2025 · 7 comments
Open

JSDoc type is not narrowing a union (but typescript does) #61339

xPaw opened this issue Mar 3, 2025 · 7 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@xPaw
Copy link

xPaw commented Mar 3, 2025

πŸ”Ž Search Terms

jsdoc union type narrow

πŸ•— Version & Regression Information

v5.8.2

⏯ Playground Link

https://www.typescriptlang.org/play/?filetype=js#code/PQKhCgAIUgBAXApgWwA4BsCGTIBUowICeqiAJogGaQDeAgqgJYBSAzgPYB2AogE6-tekAD6QGLDpwAi2TAB5cAPgC+Ypmy4AlRK1RdWiAsHDhQEaHCRosOfBeKkK1GgHkARgCtEAY3irxGtKyBHCoAqS88ES08LwAroiqrHHe3jqsIbBh7BFRtLiqZMHQxqZgmVGOVLTuXr7+6pJ8AryZ2bnRNJSY6AZJKWmsGfbtiJGdrLGMnADmqmMtRiaUiPDeABYAFJAA5Jg7kACU4AB08OuInNu8OnqcBpAAvIqQN7r6iCcekpuHR6fnS7bMyWEiIWibIrwTAALjUEi0tw+ckmvGmM0Uf2ekEwnCIqhAwEgUMwT0U4BoUEg1MYlG2AEISSdkql0v9qdTKRzuZBvPp2OhPuh2DNtkyFoIjgBuKk816rOK8Tgy7nKEzcgBumCEAGsnsTZCcSTLVIcpUA

πŸ’» Code

Typescript version: https://www.typescriptlang.org/play/?&filetype=ts#code/CYUwxgNghgTiAEAXAngBwQQVQSwFIGcB7AOwCUR9UT8QAeAFQD54BeeLPI4gURhkJjwAPuxwESAESiIoDRgG4AUItCRYCbMUQgYAMyhhMYrlJlz4Ab0Xwb8fAFcwh-PgBcSGPZBLb8YNKh3eiUAX2VVaDh4TW09AyNOEl5+QStfBycKN3h9CBofWx0U93xEGE0Ac1DlXRBEMAALAAp4AHIoVvgASkUAOkQGkGIWuEpqBBZmUapiGl6AKy4mru6+gaGWlv8Zdw5xMgoZmlpS8uIK5hXJxTTbbF0WgEJtqF6M53xV31vfGzBqQgQEC9CCECpbAK9IoCboFX7wOCIewwYhw+Bhay2ABusHgAGtWH5IS9QrCgA

πŸ™ Actual behavior

Property 'error' does not exist on type 'ApiJsonResponse<string>'.
Property 'error' does not exist on type 'ApiJsonData<string>'.

πŸ™‚ Expected behavior

No error, and for the type to be narrowed correctly.

Additional information about the issue

In my actual code, I have the types (same as in the typescript playground link), in a d.ts file. I simply converted them to jsdoc comments for the playground.

It does correctly narrow, if I change it to if( data.success === false )

@snarbles2
Copy link

The typescript version has strict null checks enabled. The javascript version does not. Enable strict null checks in the javascript version and the error goes away.

@xPaw
Copy link
Author

xPaw commented Mar 3, 2025

Is that expected behavior? Is there no way around this without enabling the check?

@snarbles2
Copy link

snarbles2 commented Mar 3, 2025

I'm not 100% sure why the type isn't narrowed without strict null checks. If I had to guess, I would say because (!data.success) narrows data.success to false | undefined, whereas (data.success === false) narrows it to false. With struct null checks, you remove undefined from the equation so both options narrow to false.

The "way around this" is to use (data.success === false) or // @ts-ignore. Otherwise, it's just doing as you asked.

@xPaw
Copy link
Author

xPaw commented Mar 3, 2025

I mean even if I type it as @property {false|undefined|null} success it doesn't want to narrow it down.

@snarbles2
Copy link

If my understanding is correct, the lack of strict null checks means undefined is always lurking around the corner which impacts the ability to narrow some things. It doesn't help to add null into the mix when what you really need is to exclude undefined. (data.success === false) does that, as does strictNullChecks, and // @ts-ignore sidesteps it.

@nmain
Copy link

nmain commented Mar 3, 2025

Duplicate of #29862.

With strictNullChecks off, it's as if you had written the type as:

type ApiJsonResponse<T> = ApiJsonError | ApiJsonData<T>;

interface ApiJsonData<T> {
    success: true | undefined | null;
    data: T;
}

interface ApiJsonError {
    success: false | undefined | null;
    error: string;
}

With that in mind, clearly if (!data.success) doesn't narrow anything.

@xPaw
Copy link
Author

xPaw commented Mar 3, 2025

That feels weird to me to be honest, it widens "true" or "false" into also undefined and null.

@RyanCavanaugh RyanCavanaugh added the Working as Intended The behavior described is the intended behavior; this is not a bug label Mar 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

4 participants