Skip to content

Erroneous type narrowing in finally #18478

Closed

Description

@Zbyl

TypeScript Version: Version 2.6.0-dev.20170914

Code

function test() {
    type YesNo = ('No' | 'Yes');
    let answer: YesNo = 'No'; // Bug disappears after adding 'as YesNo'.
    try {
        answer = 'Yes';
        return; // Bug disappears after removing the return.
    } finally {
        if (answer === 'Yes') { // Bug: Operator === cannot be applied to types 'No' and 'Yes'
        } else if (answer === 'No') {
        }
    }
}

Expected behavior:
No compilation errors.

Actual behavior:
Compilation error:
bug.ts(8,13): error TS2365: Operator '===' cannot be applied to types '"No"' and '"Yes"'.

Note:
This bug is similar to "Erroneous control flow type narrowing in loops": #15835

Activity

  1. rdsedmundo commented on Feb 6, 2019

    @rdsedmundo

    Also facing this while setup a DB connection and trying to finalize it under the finally block if it was created.

      let connection;
    
      try {
        connection = await getConnection();
    
        const { rows } = await connection.query(sql, values);
    
        return camelizeKeys(rows);
      } finally {
        if (connection) {
          // [ts] Property 'end' does not exist on type 'never'. [2339]
          await connection.end();
        }
      }
  2. dtiziani commented on Dec 12, 2019

    @dtiziani

    I'm facing the SAME issue, trying to finalize a db connection.

    What I could figure out is that it happends when a function returns anything at all, it presents the error, but if it's a void function, the issue is not present.

    Here's a playground with both scenarios: http://www.typescriptlang.org/play/?ssl=1&ssc=1&pln=29&pc=4#code/FAMwrgdgxgLglgewgAhHCATAQgTwHICGAtgKYAUExJAXMgM4wBO6A5gJS0BuCcGyA3sGTDkAGxIxkUJBBKxEEWg2YQWyAD7IIYUaOQBeLTtEBuYEJFMcAiyKky58JAa1UzdgL5SCMKAAtkMhI2Gzs7aQg6BHEAOlEEFiC2WzCYP0YEAHdkEncRLzRKXWtBMOQ4EDII2XlnAEJDbV0QiKjY+MTqxwU4klU05M8LD3NQSFqUQuwcAEkMMl4lJlYOemXVDSNdUJFxSS6JpZU1TSa9RuMzFKsd8IcJl14rsuFGCTBGFAOnCDzhLygPn8gWCtzCrWiJDiCSSKTsaQy2VyKQK6AIxTBwgqVXuP2QDS2ohaSDaUI6OIgNR+vX6fkG+WGQA

    also the code below:

    
    // No issues at all
    function findByName(name: string): void {
        let connection: string | null = null;
    
        try {
          connection = name;
        } catch (e) {
            console.log(e)
            throw e;
        } finally {
          if(connection != null) console.log(connection.length)
        }
      }
    
    // variable connection as never on finally block
    function findById(id: string): string | null {
        let connection: string | null = null;
    
        try {
          connection = id;
    
            return connection;
        } catch (e) {
            console.log(e)
            throw e;
        } finally {
          if(connection != null) console.log(connection.length)
        }
      }
    
    
  3. SlurpTheo commented on Jan 9, 2020

    @SlurpTheo

    I can't reproduce the earlier problems in this issue anymore (using typescript@3.7.4), but I do get the same CFA problem described by Daniel Tiziani (@dtiziani) in the findById()-example.

    Commenting-out either the return or the throw statement prevents the problem.


    Now, if you slightly tweak the example (to use undefined instead of null), there's another interesting bit that not explicitly initializing to = undefined prevents the problem as well:

    function findById2(id: string) {
       // not explicitly initializing this to `= undefined` prevents the problem
       let connection: string | undefined = undefined;
    
       try {
          connection = id;
    
          // commenting-out this `return` -OR- the `throw` below prevents the problem
          return connection;
       } catch (e) {
          console.log(e);
    
          // commenting-out this `throw` -OR- the `return` above prevents the problem
          throw e;
       } finally {
          if (connection) {
             // ts(2339) -
             //   Property 'length' does not exist on type 'never'.
             console.log(connection.length);
          }
       }
    }

    And this "work-around" reminds me of this CFA conversation... only there's no function expression involved.

  4. RyanCavanaugh commented on Jan 9, 2020

    @RyanCavanaugh
    Member

    SlurpTheo fixed in nightly; see #34880

  5. locked as resolved and limited conversation to collaborators on Oct 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

BugA bug in TypeScriptFixedA PR has been merged for this issue

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions