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

Unconstrained type parameter has stricter comparability rules than extends unknown #48680

Closed
DanielRosenwasser opened this issue Apr 13, 2022 · 3 comments · Fixed by #48861
Closed
Assignees
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue

Comments

@DanielRosenwasser
Copy link
Member

Fine in 4.7 and 4.6

function foo<T extends unknown>() {
    let x = {};
    x as T;
}

Fine in 4.6, fails in 4.7

function foo<T>() {
    let x = {};
    x as T;
}
@DanielRosenwasser DanielRosenwasser added the Bug A bug in TypeScript label Apr 13, 2022
@DanielRosenwasser DanielRosenwasser added this to the TypeScript 4.7.1 milestone Apr 13, 2022
@weswigham
Copy link
Member

Weird. I wonder what comparability is doing to make this happen.

@DanielRosenwasser
Copy link
Member Author

Probably this #32814

@weswigham
Copy link
Member

weswigham commented Apr 27, 2022

So comparability, as a relation, is in a very bad way from a consistency perspective right now.

Take this, for example:

enum E { a, b, c }
    
declare var a: boolean;
declare var b: number;
declare var c: string;
declare var d: void;
declare var e: E;
declare var f: { a: string };
declare var g: any[];

function fn<T>(t: T) {
  var r8a1 = t < a;
  var r8a2 = t < b;
  var r8a3 = t < c;
  var r8a4 = t < d;
  var r8a5 = t < e;
  var r8a6 = t < f;
  var r8a7 = t < g;
  var r8b1 = a < t;
  var r8b2 = b < t;
  var r8b3 = c < t;
  var r8b4 = d < t;
  var r8b5 = e < t;
  var r8b6 = f < t;
  var r8b7 = g < t;
}

this is an except from our tests. All of these comparisons are forbidden (because instantiation may make the comparison forbidden, was our stated logic in the relevant issue). However, this

enum E { a, b, c }
    
declare var a: boolean;
declare var b: number;
declare var c: string;
declare var d: void;
declare var e: E;
declare var f: { a: string };
declare var g: any[];

function fn<T extends unknown>(t: T) {
  var r8a1 = t < a;
  var r8a2 = t < b;
  var r8a3 = t < c;
  var r8a4 = t < d;
  var r8a5 = t < e;
  var r8a6 = t < f;
  var r8a7 = t < g;
  var r8b1 = a < t;
  var r8b2 = b < t;
  var r8b3 = c < t;
  var r8b4 = d < t;
  var r8b5 = e < t;
  var r8b6 = f < t;
  var r8b7 = g < t;
}

is the same but with one small difference - an explicit constraint. This currently issues no errors on any comparison, despite ostensibly being identical. This is, perhaps obviously, terribly inconsistent.

The request in the OP of this thread, that

function foo<T>() {
    let x = {};
    x as T;
}

be allowed, implies that all of the comparisons I listed above should be allowed. It's certainly doable (and in fact done, implementation on-hand over in #48861). Conversely, if in presenting this inconsistency I've changed your mind and now you think all these comparisons should be forbidden, we need to add a lot of errors to constrained type parameters in comparability (which is going to be much more breaking)!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue
Projects
None yet
3 participants