Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generic bounds not enforced on generic argument #32330

Closed
evmar opened this issue Jul 10, 2019 · 3 comments · Fixed by #48366
Closed

Generic bounds not enforced on generic argument #32330

evmar opened this issue Jul 10, 2019 · 3 comments · Fixed by #48366
Assignees
Labels
Breaking Change Would introduce errors in existing code Bug A bug in TypeScript Fix Available A PR has been opened for this issue Rescheduled This issue was previously scheduled to an earlier milestone

Comments

@evmar
Copy link
Contributor

evmar commented Jul 10, 2019

TypeScript Version: [email protected], 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:

@evmar
Copy link
Contributor Author

evmar commented Jul 10, 2019

Perhaps a simpler expression of this is

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

Which I also expect should fail.

@RyanCavanaugh
Copy link
Member

@weswigham ?

@weswigham
Copy link
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.

@RyanCavanaugh RyanCavanaugh added the Needs Investigation This issue needs a team member to investigate its status. label Jul 12, 2019
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 3.7.0 milestone Jul 12, 2019
@weswigham weswigham added Bug A bug in TypeScript and removed Needs Investigation This issue needs a team member to investigate its status. labels Sep 24, 2019
@weswigham weswigham added Breaking Change Would introduce errors in existing code Fix Available A PR has been opened for this issue labels Feb 6, 2020
@RyanCavanaugh RyanCavanaugh added the Rescheduled This issue was previously scheduled to an earlier milestone label Aug 31, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Breaking Change Would introduce errors in existing code Bug A bug in TypeScript Fix Available A PR has been opened for this issue Rescheduled This issue was previously scheduled to an earlier milestone
Projects
None yet
5 participants