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

Compiler is unable to resolve return type of function even though it is returning function with known return type #26623

Description

@devuxer

TypeScript Version: 3.0.1

Search Terms:

  • "implicitly has return type 'any'"
  • TS7023

Code

interface Identifiable {
    name: string;
    nickname: string;
    isNameSameAsNickname: boolean;
}

class Person implements Identifiable {
    public name = "Baz";
    public nickname = "Baz";

    get isNameSameAsNickname() {
        return compareNames(this);
    }
}

function compareNames(identifiable: Identifiable) {
    return identifiable.name === identifiable.nickname;
}

Expected behavior:

Compiles without error

Actual behavior:

The following error occurs:

TS7023: 'isNameSameAsNickname' implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions.

Comment: This error appears to be incorrect (or at least worded ambiguously) because isNameSameAsNickname is not referenced directly or indirectly in one of its return expressions. Specifically, isNameSameAsNickname does not appear directly in the return expression compareNames(this) nor does it appear indirectly in identifiable.name === identifiable.nickname.

Workaround:

Declare the return type explicitly:

get isNameSameAsNickname(): boolean {
    return compareNames(this);
}

Playground Link:

This error is indicated in the playground with a red squiggle below isNameSameAsNickname().

Note: Error only occurs if noImplicitAny option is checked

Related Issues:

Activity

  1. changed the title [-]Returning a function with a known return type[/-] [+] Compiler is unable to resolve return type of function even though it is returning function with known return type[/+] on Aug 23, 2018
  2. RyanCavanaugh commented on Aug 23, 2018

    @RyanCavanaugh
    Member

    This is a circular operation, because we have to check what the type of Person#isNameSameAsNickname is in order to check the call to compareNames to figure out what the return type could be. You can see this because removing isNameSameAsNickname from Identifiable causes the error to go away.

  3. devuxer commented on Aug 23, 2018

    @devuxer
    Author

    Ryan Cavanaugh (@RyanCavanaugh),

    Thanks for your reply. So it sounds like you are saying, the compiler is undergoing the following "thought" process:

    1. Okay, so isSameAsNickname depends on compareNames.
    2. And compareNames requires an Identifiable as input.
    3. And an Identifiable must have a property, isNameSameAsNickname, that returns a boolean.
    4. Therefore, compareNames depends on isNameSameAsNickname.
    5. Damn, this is complicated, I give up.

    Meanwhile, the human being (me) is undergoing a different thought process:

    1. Okay, so isNameSameAsNickname depends on compareNames.
    2. And compareNames returns a boolean.
    3. Therefore isNameSameAsNickname must return a boolean.
    4. Therefore Person is a legitimate Identifiable.
    5. Therefore compareNames can be called.

    This suggests that the order that type checks are performed has a significant effect on whether dependencies resolve or are deemed circular. On the surface, this seems like it shouldn't be hard to fix, but I gather it's a difficult problem or it would already be solved.

    This does bring up a question...

    The workaround I provided is obviously very simple to implement, so I'm OK using that, but is there a better, more "best practices" way to accomplish this type of thing that avoids this issue altogether?

  4. RyanCavanaugh commented on Aug 24, 2018

    @RyanCavanaugh
    Member

    I gather it's a difficult problem or it would already be solved.

    Yep 😉. The real issue here is that the two main operations the checker does - inference and error detection - occur at the "same time". You could imagine a different world where all inference happens, then all error checking happens, which would avoid this problem because the check of whether the argument type is assignable to the parameter type would only be part of the error-checking phase. But this would likely be at least twice as slow as the current implementation.

    There's no set practice that will avoid all circularity issues. The return type annotation is the best alternative for this example, I would say.

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