Skip to content

Extend scope of narrowed consts #10501

Closed
Closed

Description

@jods4

This is a suggestion to lift a limitation of the current flow analysis.

Consider this, with strict null checks:

function f() {
  let name: string | null = frob();
  if (!name) return;
  bar(() => name.length);  // Error possibly null name
}

TS does not propagate type guards accross function captures.
Rightly so because we don't know when the lambda will actually be called. It can be called much later and at that point name might be null again. E.g. if right after bar(...) we have name = null.

Now, consider this variation:

function f() {
  const name: string | null = frob();
  if (!name) return;
  bar(() => name.length);  // Error possibly null name
}

I suggest that because name is declared with const, it can't change. So if at the point of capture it has a not null type guard, then it is correct to propagate this information inside the lambda.
👉 The second example can compile without error.

Activity

  1. RyanCavanaugh commented on Aug 23, 2016

    @RyanCavanaugh
    Member

    This is already not an error in master.

  2. jods4 commented on Aug 23, 2016

    @jods4
    Author

    Sorry it seems my short repro was not good enough.
    After testing the code above works even on 2.0.0, but try this instead:

    function f() {
      const x: string | null = frob();
      if (!x)
        return {
          bar() { return x.length; }  // Error: possibly null x
        };
    }

    Not sure what the difference is here... Method in object literals are considered differently than plain lambdas?

  3. RyanCavanaugh commented on Aug 23, 2016

    @RyanCavanaugh
    Member
    function f() {
      const x: string | null = <any>{};
      if (x !== null) {
        return {
          bar() { return x.length; }  // Error: possibly null x
        };
      }
    }
  4. ahejlsberg commented on Aug 23, 2016

    @ahejlsberg
    Member

    Currently we only extend const type guards to nested function expressions and arrow functions, but we ought to also include methods in object literals and class expressions. Until we have a fix, the easy workaround for object literals is to just use regular properties and function expressions. For example, this works:

    function f() {
      const x: string | null = <any>{};
      if (x !== null) {
        return {
          bar: function() { return x.length; }  // Ok
        };
      }
    }
  5. added a commit that references this issue on Oct 8, 2016
    402f1f6
  6. locked and limited conversation to collaborators on Jun 19, 2018
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