Skip to content

Generic bounds not enforced on generic argument #32330

Closed

Description

@evmar

TypeScript Version: typescript@3.6.0-dev.20190710, 3.5.1

Search Terms: generic bounds toString

Code

function f1<T>(o: T) {
  o.toString(); // error
  // This is expected, because T might be undefined or null
}

function f2<T extends {}>(o: T) {
  o.toString(); // no error
  // This is expected, this is the correct way to fix the above function.
}

function user<T>(t: T) {
  f1(t);  // Allowed, but irrelevant because f1() is invalid
  f2(t);  // Allowed?  <- this is the bug
  t.toString();  // Error, expected for the same reason as f1()
}

Expected behavior:
You should not be able to pass an arbitrary T into a function that demands T extends {}.

Actual behavior:
Despite .toString() being disallowed both in user() and in f1(), you can just pass it to f2() and still call toString on the same value.

Playground Link:
http://www.typescriptlang.org/play/#code/GYVwdgxgLglg9mABMAjAHgCoD4AUcBciGAlIgN4BQiicAdFHAMpQBOMYA5jsQNwUC+FCqEiwEyAEyZEAUwAeUGWAAmAZ3L9cBIqUrU6DZm07c+g4eGjwkIVTJaZcUQiXJVkKHFF7vgErz7UUPRMrOxcPuZAA

Related Issues:

Activity

  1. evmar commented on Jul 10, 2019

    @evmar
    ContributorAuthor

    Perhaps a simpler expression of this is

    function user<T>(t: T) {
      let o: {} = t;
    }

    Which I also expect should fail.

  2. RyanCavanaugh commented on Jul 10, 2019

    @RyanCavanaugh
    Member
  3. weswigham commented on Jul 10, 2019

    @weswigham
    Member

    Is an old special assignability rule case left over from when the default for an unconstrained type parameter was {} instead of unknown, I believe. I think it's just a matter of deleting these lines:

                            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;
                                }
                            }

    in checker.ts - but the impact of doing so will need to be checked, ofc.

  4. added
    BugA bug in TypeScript
    and removed
    Needs InvestigationThis issue needs a team member to investigate its status.
    on Sep 24, 2019
  5. 13 remaining items

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

Breaking ChangeWould introduce errors in existing codeBugA bug in TypeScriptFix AvailableA PR has been opened for this issueRescheduledThis issue was previously scheduled to an earlier milestone

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions