镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

Generalize never type handling for control flow analysis based type guard #12825

Description

@vilicvane

I guess there would be some duplicates, but I cannot find it.

TypeScript Version: 2.1.14

Code

function throwError(): never {
    throw new Error();
}

let foo: string | undefined;

if (!foo) {
    throwError();
}

foo; // Expected to be `string` instead of `string | undefined`.

Activity

  1. akarzazi commented on Dec 10, 2016

    @akarzazi

    It would be a great way to control the flow.

    For now, you may use return if your are inside a function.

    function throwError(): never {
        throw new Error();
    }
    
    let foo: string | undefined;
    if (!foo) {
        throwError();
        return:
    }
    foo; // foo is string

    or use a check typeguard

    function throwError(): never {
        throw new Error();
    }
    
    // Inferred return type is T
    function check<T>(x: T | undefined) {
        return x || throwError();
    }
    
    let foo: string | undefined;
    
    let foosafe = check(foo); // foosafe is string
  2. yortus commented on Dec 11, 2016

    @yortus
    Contributor

    Related: #8655

  3. dhedey commented on Aug 14, 2017

    @dhedey

    I'd like to echo my support for this. Currently to get control flow analysis to work correctly in our codebase (which make use of a framework requiring the use of an external throwError style method), we explicitly throw ''; // See https://github.com/Microsoft/TypeScript/issues/12825 in the following line.

    ADDENDUM:

    I've just noted RyanCavanaugh's comment on a duplicate thread.

    The recommended workaround is to write return throwError();

    We'll use this workaround from now on. It appears to not interfere with the returned type. 👍

    if (!foo) {
        return throwError();
    }
  4. masaeedu commented on Nov 18, 2017

    @masaeedu
    Contributor

    I currently use const guaranteedFoo = foo || throwError() to strip away undefined from stuff that I know should never be undefined.

  5. masaeedu commented on Apr 15, 2018

    @masaeedu
    Contributor

    Parzh (org) (@parzh) Depends on what your value's type is. If the type is { foo: string } | undefined, you already know it's not 0, false, or any of those other things. If you do indeed have a mixed type that could contain booleans and strings and a multitude of other things, you should do a more specific check: foo !== undefined || throwError().

  6. ypresto commented on Aug 30, 2018

    @ypresto
    Contributor

    I got Object is possibly 'undefined' error after try { ... } catch (e) { ...; process.exit(1) } in node.
    I expected that process.exit(1) behave like throw for type inference.

  7. simonbuchan commented on Mar 12, 2019

    @simonbuchan

    For other people googling this, this issue was addressed in #14490. Basically it seems the issue is TS currently has separate passes for flow control and type assignment, and the former needs to run first for the latter to work, and there didn't seem to be any clean solutions that would also handle imported functions, etc....
    So the current workaround is just return neverReturningFunction();, which won't alter the return type and lets flow control do its thing.

  8. Kinrany commented on Mar 21, 2021

    @Kinrany

    The workaround doesn't work in top-level code outside functions, since there's no return there.

  9. fcole90 commented on Aug 11, 2021

    @fcole90

    Ruslan Fadeev (@Kinrany) you can still use the other workaround val !== undefined || throw new Error()

  10. jakebailey commented on Apr 8, 2024

    @jakebailey
    Member

    The original code in this issue has been working as expected for a while. Is there anything else above that isn't right? I'm thinking no, and that this issue can be closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    In DiscussionNot yet reached consensusSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions