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

the types 'T' and (anything else) have no overlap #32768

Description

@davidje13

TypeScript Version: 3.5.3

Search Terms:

  • Generic "has no overlap"

Code

const num = 1;
function check<T>(x: T) {
  return x === num;
}
check(num);

Expected behavior:

No error; check returns true if given num (or an alias of it), and false otherwise.

Actual behavior:

index.ts:3:10 - error TS2367: This condition will always return 'false' since the types 'T' and '1' have no overlap.

3   return x === num;
           ~~~~~~~~~


Found 1 error.

I observed this in a slightly more complex case but with the same idea:

const makeNum = () => 1;
function check<T>(f: () => T) {
  return f === makeNum;
}
check(makeNum);

Playground Link:
https://www.typescriptlang.org/play/#code/MYewdgzgLgBGCuBbGBeGBGA3AKAGbzGCgEtwZgALAU2AGsAeAFQD4AKADwC4ZGBKGAN7YYMAE5Uo8UWBjtUKNAkQ4Avtko1arJb0xA

Activity

  1. davidje13 commented on Aug 8, 2019

    @davidje13
    Author

    My use-case approximates to the following:

    const isNum = (v: unknown) => {
      if (typeof v !== 'number') throw new Error('Not a number');
      return v;
    };
    const isString = (v: unknown) => {
      if (typeof v !== 'string') throw new Error('Not a string');
      return v;
    };
    
    function makeExampleValue<T>(validator: (v: unknown) => T): T {
      if (parser === isNum) return 42;
      if (parser === isString) return 'something';
      throw new Error('unknown type');
    }

    I'm considering restructuring to avoid the need for what is effectively a switch in a monolith function, but the reported error is incorrect in any case.

  2. AnyhowStep commented on Aug 8, 2019

    @AnyhowStep
    Contributor

    T extends unknown?

  3. davidje13 commented on Aug 9, 2019

    @davidje13
    Author

    AnyhowStep that works, so I guess I'm confused why <T> and <T extends unknown> are different (i.e. why isn't extends unknown the default assumption?)

  4. AnyhowStep commented on Aug 9, 2019

    @AnyhowStep
    Contributor

    If it can't infer T, it should default to unknown in your case (since you didn't specify a constraint type).

    As for why you need to explicitly add extends unknown for your equality check to work, even though extends unknown should be implicit...

    ¯\(ツ)/¯

  5. RyanCavanaugh commented on Aug 9, 2019

    @RyanCavanaugh
    Member

    Daniel Rosenwasser (@DanielRosenwasser) what's the reasoning behind the current comparability rules with type parameters?

  6. jack-williams commented on Aug 9, 2019

    @jack-williams
    Collaborator

    AnyhowStep

    As for why you need to explicitly add extends unknown for your equality check to work, even though extends unknown should be implicit

    Without an explicit constraint I think the default constraint used is the empty object type (if you do extends {} you get the same result as with no constraint).

    const constraint = getConstraintOfType(<TypeVariable>source);
    if (!constraint || (source.flags & TypeFlags.TypeParameter && constraint.flags & TypeFlags.Any)) {
        // A type variable with no constraint is not related to the non-primitive object type.
        if (result = isRelatedTo(emptyObjectType, extractTypesOfKind(target, ~TypeFlags.NonPrimitive))) {
            errorInfo = saveErrorInfo;
            return result;
        }
    }

    I'm wondering if this was just a missed case in #30637?

  7. DanielRosenwasser commented on Aug 9, 2019

    @DanielRosenwasser
    Member

    Ryan Cavanaugh (@RyanCavanaugh) number is not comparable to T, and T isn't comparable to number (because unknown - T's constraint - isn't comparable to number).

    We have another issue open about this, but if you tried to "fix" it, you might end up with weird behavior where two unrelated type parameters T and U can be checked for equality. While it's not unsound, it allows questionable code.

  8. RyanCavanaugh commented on Aug 12, 2019

    @RyanCavanaugh
    Member

    Daniel Rosenwasser (@DanielRosenwasser)

    because unknown - T's constraint - isn't comparable to number

    unknown is comparable to number, and the example works if T is explicit constrained to unknown (which should (???) be a no-op by my understanding).

  9. DanielRosenwasser commented on Aug 12, 2019

    @DanielRosenwasser
    Member

    unknown is comparable to number

    It's actually the other way around - number is comparable to unknown. Comparability is still a unidirectional relationship that we happen to apply in two directions.

    and the example works if T is explicit constrained to unknown (which should (???) be a no-op by my understanding).

    I would consider that a bug, and I've opened #32814 to track it. I would guess it's likely either a bug in our getApparentType logic, or in the way we get implicit constraints, or we have some weird special unknown type we're not doing the right thing with.

  10. added
    DuplicateAn existing issue was already created
    and removed
    BugA bug in TypeScript
    on Aug 12, 2019
  11. RyanCavanaugh commented on Aug 12, 2019

    @RyanCavanaugh
    Member

    We're going to track this at #32814 for clarity

  12. typescript-bot commented on Aug 15, 2019

    @typescript-bot
    Contributor

    This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

  13. weswigham commented on Aug 15, 2019

    @weswigham
    Member

    Without an explicit constraint I think the default constraint used is the empty object type

    FYI, the default base constraint is unknown nowadays - we swapped a few releases ago.

  14. jack-williams commented on Aug 15, 2019

    @jack-williams
    Collaborator

    Yeah I knew the design had changed, but I wasn't sure if a case had been missed. That code looked related, though tbh, I'm not really sure what's going on.

  15. 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

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions