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

nullable object type does not narrow with a "never" function #52784

Closed
ArcticZeroo opened this issue Feb 15, 2023 · 3 comments
Closed

nullable object type does not narrow with a "never" function #52784

ArcticZeroo opened this issue Feb 15, 2023 · 3 comments
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed

Comments

@ArcticZeroo
Copy link

ArcticZeroo commented Feb 15, 2023

Bug Report

πŸ”Ž Search Terms

some variations/permutations of "narrow never null"

πŸ•— Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about type narrowing/never functions

⏯ Playground Link

Playground link with relevant code

πŸ’» Code

const throwError = (): never => { throw new Error(); };
const someFunc = (): string | undefined => "hello world";

const getA = (): string => {
    const a = someFunc();

    if (!a) {
        throwError();
    }

    return a;
}

πŸ™ Actual behavior

Compilation fails because TS thinks that a may be null when returning it from getA.

πŸ™‚ Expected behavior

Because throwError is never, TS should be able to see that I will never reach the return statement if a is null (or falsy at all). Even if I explicitly check for if (a == null), control flow analysis does not seem to narrow the type here.

So, expected behavior is that compilation succeeds and the type is narrowed to just string.

I see this related issue which implies that I should be able to narrow my type by calling a never function: #50739 , but I cannot reproduce the behavior of narrowing a.

@RyanCavanaugh
Copy link
Member

throwError needs a type annotation:

const throwError: () => never = (): never => { throw new Error(); };

This is a limitation of CFA on never-returning functions; see #32695

@RyanCavanaugh RyanCavanaugh added the Design Limitation Constraints of the existing architecture prevent this from being fixed label Feb 15, 2023
@ArcticZeroo
Copy link
Author

Thanks for the info @RyanCavanaugh .

Is there any way to add that explicit type annotation on interface methods? I ran into this issue specifically when working with the koa webserver. I was trying to call ctx.throw, which is defined here: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/koa/index.d.ts#L691

I've tried redefining them locally as throw: (...) => never but that doesn't seem to satisfy the compiler.

@fatcerberus
Copy link

fatcerberus commented Feb 16, 2023

As part of an interface, the method is already explicitly typed.

However, if you’re calling it as a method, then the object it’s called through (ctx in this case) also must have an explicit type annotation. The relevant text from #32695 is:

A function call is analyzed as an assertion call or never-returning call when … each identifier in the function name references an entity with an explicit type … and
the function name resolves to a function type with an asserts return type or an explicit never return type annotation.

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