Skip to content

Unable to resolve a const variable type with nested ref with noImplicitAny enabled #17386

Closed

Description

@takamori

TypeScript Version: 2.4.0 / nightly (2.5.0-dev.201xxxxx)

Code

function hello() {
  let lastThing = null;
  for (let i = 0; i < 2; i++) {
    const thing = new Thing(!lastThing ? null : lastThing);
    lastThing = thing;
  }
}

class Thing  {
  constructor(public readonly prior: Thing|null) {
  }
}

Expected behavior:
Since thing is being defined directly, the compiler should still intuit that it's of type Thing when noImplicitAny is enabled.

Actual behavior:
The compiler doesn't like the nested data reference via the loop and lastThing reference and says thing will be "any" and I have to explicitly define thing as type Thing:

'thing' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.

This is a simplified version of the actual code; the existence of a loop and the reference to the prior instance are critical to the actual usage. Repros with the TS playground with noImplicitAny enabled.

Activity

  1. takamori commented on Jul 25, 2017

    @takamori
    Author

    I should have noted that we also have strictNullChecks enabled as well; defining the type of lastThing doesn't help.

    function hello() {
      let lastThing: Thing|null = null;
      for (let i = 0; i < 2; i++) {
        const thing = new Thing(!lastThing ? null : lastThing);
        lastThing = thing;
      }
    }
    
    class Thing  {
      constructor(public readonly prior: Thing|null) {
      }
    }
  2. mhegazy commented on Aug 24, 2017

    @mhegazy
    Contributor

    The problem is not Thing declaration location, it is that type of thing depends on type of lastThing, whose type inside the loop depends on the type of thing. giving thing an explicit type would resolve the circular dependency and avoid the any type.

  3. takamori commented on Aug 24, 2017

    @takamori
    Author

    Thanks for your response. I didn't understand the logic behind what you wrote, unfortunately.

    1. Shouldn't lastThing's type be sufficiently validated to be either Thing or null, with the explicit declaration of lastThing's type as in my second post? Is the explicit declaration not trusted?

    2. I also don't understand why the type of thing depends on the type of lastThing. Can you clarify that? It would seem to me that the invocation of a constructor of a type should restrict the resulting value to be that type. Is that not trusted?

  4. mhegazy commented on Aug 25, 2017

    @mhegazy
    Contributor

    The compiler tries to do control flow analysis to know the types of variables at a given locaiton. this is what allows things like var x: string | null; if(x) x.length; since the compiler knows that insider the if statement x can nto be null.
    similarly in a loop, the compiler tries to figure out what the type of lastThing is. remember a loop body has two possible entry points, either from the top on first iteration, or from the end of previous iterations; so because of the assignment it is the type of thing, but to know the type of thing, it needs to resolve a call to new Thing and to do that it needs to know what is lastThing, but it was trying to figure out that in the first place.
    The compiler uses any to break such ties, and flags that when --noImplictAny is set.

  5. takamori commented on Aug 25, 2017

    @takamori
    Author

    Thanks for the clarification, and I see how the "Design Limitation" label applies here now.

  6. mhegazy commented on Sep 8, 2017

    @mhegazy
    Contributor

    Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.

  7. locked and limited conversation to collaborators on Jun 14, 2018
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

    Design LimitationConstraints of the existing architecture prevent this from being fixed

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions