Skip to content

Commit 108f9d7

Browse files
committed
Use never as type argument for contravariant type parameters
Signed-off-by: Michael Molisani <[email protected]>
1 parent d656065 commit 108f9d7

11 files changed

+1031
-24
lines changed

src/compiler/checker.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -8846,7 +8846,14 @@ namespace ts {
88468846
return classType;
88478847
}
88488848
const typeArguments = map(classType.typeParameters, typeParameter => {
8849-
return (inferInstanceTypeArgumentsAsConstraint) ? getBaseConstraintOfType(typeParameter) || unknownType : anyType;
8849+
if (!inferInstanceTypeArgumentsAsConstraint) {
8850+
return anyType;
8851+
}
8852+
const modifiers = getVarianceModifiers(typeParameter);
8853+
if (modifiers & ModifierFlags.In) {
8854+
return neverType;
8855+
}
8856+
return getBaseConstraintOfType(typeParameter) || unknownType;
88508857
});
88518858
return createTypeReference(classType as GenericType, typeArguments);
88528859
}

tests/baselines/reference/inferInstanceTypeArgumentsAsConstraint.errors.txt

+15-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
tests/cases/compiler/inferInstanceTypeArgumentsAsConstraint.ts(8,13): error TS2339: Property 'toUpperCase' does not exist on type 'unknown'.
2-
tests/cases/compiler/inferInstanceTypeArgumentsAsConstraint.ts(9,5): error TS2356: An arithmetic operand must be of type 'any', 'number', 'bigint' or an enum type.
3-
tests/cases/compiler/inferInstanceTypeArgumentsAsConstraint.ts(10,7): error TS2349: This expression is not callable.
1+
tests/cases/compiler/inferInstanceTypeArgumentsAsConstraint.ts(9,13): error TS2339: Property 'toUpperCase' does not exist on type 'unknown'.
2+
tests/cases/compiler/inferInstanceTypeArgumentsAsConstraint.ts(10,5): error TS2356: An arithmetic operand must be of type 'any', 'number', 'bigint' or an enum type.
3+
tests/cases/compiler/inferInstanceTypeArgumentsAsConstraint.ts(11,7): error TS2349: This expression is not callable.
44
Type '{}' has no call signatures.
5+
tests/cases/compiler/inferInstanceTypeArgumentsAsConstraint.ts(35,12): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
56

67

7-
==== tests/cases/compiler/inferInstanceTypeArgumentsAsConstraint.ts (3 errors) ====
8+
==== tests/cases/compiler/inferInstanceTypeArgumentsAsConstraint.ts (4 errors) ====
89
class Unconstrained<T> {
910
value: T;
11+
read: (value: T) => void;
1012
}
1113

1214
declare const x: unknown;
@@ -29,15 +31,24 @@ tests/cases/compiler/inferInstanceTypeArgumentsAsConstraint.ts(10,7): error TS23
2931
if (typeof x.value === "number") {
3032
x.value++;
3133
}
34+
35+
x.read(1);
36+
x.read("foo");
3237
}
3338

3439
class Constrained<T extends number> {
3540
value: T;
41+
read: (value: T) => void;
3642
}
3743

3844
declare const y: unknown;
3945

4046
if (y instanceof Constrained) {
4147
y.value++;
48+
49+
y.read(1);
50+
y.read("foo");
51+
~~~~~
52+
!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
4253
}
4354

tests/baselines/reference/inferInstanceTypeArgumentsAsConstraint.js

+12
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//// [inferInstanceTypeArgumentsAsConstraint.ts]
22
class Unconstrained<T> {
33
value: T;
4+
read: (value: T) => void;
45
}
56

67
declare const x: unknown;
@@ -16,16 +17,23 @@ if (x instanceof Unconstrained) {
1617
if (typeof x.value === "number") {
1718
x.value++;
1819
}
20+
21+
x.read(1);
22+
x.read("foo");
1923
}
2024

2125
class Constrained<T extends number> {
2226
value: T;
27+
read: (value: T) => void;
2328
}
2429

2530
declare const y: unknown;
2631

2732
if (y instanceof Constrained) {
2833
y.value++;
34+
35+
y.read(1);
36+
y.read("foo");
2937
}
3038

3139

@@ -45,6 +53,8 @@ if (x instanceof Unconstrained) {
4553
if (typeof x.value === "number") {
4654
x.value++;
4755
}
56+
x.read(1);
57+
x.read("foo");
4858
}
4959
var Constrained = /** @class */ (function () {
5060
function Constrained() {
@@ -53,4 +63,6 @@ var Constrained = /** @class */ (function () {
5363
}());
5464
if (y instanceof Constrained) {
5565
y.value++;
66+
y.read(1);
67+
y.read("foo");
5668
}

tests/baselines/reference/inferInstanceTypeArgumentsAsConstraint.symbols

+49-19
Original file line numberDiff line numberDiff line change
@@ -5,74 +5,104 @@ class Unconstrained<T> {
55

66
value: T;
77
>value : Symbol(Unconstrained.value, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 0, 24))
8+
>T : Symbol(T, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 0, 20))
9+
10+
read: (value: T) => void;
11+
>read : Symbol(Unconstrained.read, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 1, 13))
12+
>value : Symbol(value, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 2, 11))
813
>T : Symbol(T, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 0, 20))
914
}
1015

1116
declare const x: unknown;
12-
>x : Symbol(x, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 4, 13))
17+
>x : Symbol(x, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 5, 13))
1318

1419
if (x instanceof Unconstrained) {
15-
>x : Symbol(x, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 4, 13))
20+
>x : Symbol(x, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 5, 13))
1621
>Unconstrained : Symbol(Unconstrained, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 0, 0))
1722

1823
x.value.toUpperCase();
1924
>x.value : Symbol(Unconstrained.value, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 0, 24))
20-
>x : Symbol(x, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 4, 13))
25+
>x : Symbol(x, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 5, 13))
2126
>value : Symbol(Unconstrained.value, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 0, 24))
2227

2328
x.value++;
2429
>x.value : Symbol(Unconstrained.value, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 0, 24))
25-
>x : Symbol(x, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 4, 13))
30+
>x : Symbol(x, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 5, 13))
2631
>value : Symbol(Unconstrained.value, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 0, 24))
2732

2833
x.value();
2934
>x.value : Symbol(Unconstrained.value, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 0, 24))
30-
>x : Symbol(x, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 4, 13))
35+
>x : Symbol(x, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 5, 13))
3136
>value : Symbol(Unconstrained.value, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 0, 24))
3237

3338
if (typeof x.value === "string") {
3439
>x.value : Symbol(Unconstrained.value, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 0, 24))
35-
>x : Symbol(x, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 4, 13))
40+
>x : Symbol(x, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 5, 13))
3641
>value : Symbol(Unconstrained.value, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 0, 24))
3742

3843
x.value.toUpperCase();
3944
>x.value.toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --))
4045
>x.value : Symbol(Unconstrained.value, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 0, 24))
41-
>x : Symbol(x, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 4, 13))
46+
>x : Symbol(x, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 5, 13))
4247
>value : Symbol(Unconstrained.value, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 0, 24))
4348
>toUpperCase : Symbol(String.toUpperCase, Decl(lib.es5.d.ts, --, --))
4449
}
4550
if (typeof x.value === "number") {
4651
>x.value : Symbol(Unconstrained.value, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 0, 24))
47-
>x : Symbol(x, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 4, 13))
52+
>x : Symbol(x, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 5, 13))
4853
>value : Symbol(Unconstrained.value, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 0, 24))
4954

5055
x.value++;
5156
>x.value : Symbol(Unconstrained.value, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 0, 24))
52-
>x : Symbol(x, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 4, 13))
57+
>x : Symbol(x, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 5, 13))
5358
>value : Symbol(Unconstrained.value, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 0, 24))
5459
}
60+
61+
x.read(1);
62+
>x.read : Symbol(Unconstrained.read, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 1, 13))
63+
>x : Symbol(x, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 5, 13))
64+
>read : Symbol(Unconstrained.read, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 1, 13))
65+
66+
x.read("foo");
67+
>x.read : Symbol(Unconstrained.read, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 1, 13))
68+
>x : Symbol(x, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 5, 13))
69+
>read : Symbol(Unconstrained.read, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 1, 13))
5570
}
5671

5772
class Constrained<T extends number> {
58-
>Constrained : Symbol(Constrained, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 17, 1))
59-
>T : Symbol(T, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 19, 18))
73+
>Constrained : Symbol(Constrained, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 21, 1))
74+
>T : Symbol(T, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 23, 18))
6075

6176
value: T;
62-
>value : Symbol(Constrained.value, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 19, 37))
63-
>T : Symbol(T, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 19, 18))
77+
>value : Symbol(Constrained.value, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 23, 37))
78+
>T : Symbol(T, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 23, 18))
79+
80+
read: (value: T) => void;
81+
>read : Symbol(Constrained.read, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 24, 13))
82+
>value : Symbol(value, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 25, 11))
83+
>T : Symbol(T, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 23, 18))
6484
}
6585

6686
declare const y: unknown;
67-
>y : Symbol(y, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 23, 13))
87+
>y : Symbol(y, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 28, 13))
6888

6989
if (y instanceof Constrained) {
70-
>y : Symbol(y, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 23, 13))
71-
>Constrained : Symbol(Constrained, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 17, 1))
90+
>y : Symbol(y, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 28, 13))
91+
>Constrained : Symbol(Constrained, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 21, 1))
7292

7393
y.value++;
74-
>y.value : Symbol(Constrained.value, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 19, 37))
75-
>y : Symbol(y, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 23, 13))
76-
>value : Symbol(Constrained.value, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 19, 37))
94+
>y.value : Symbol(Constrained.value, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 23, 37))
95+
>y : Symbol(y, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 28, 13))
96+
>value : Symbol(Constrained.value, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 23, 37))
97+
98+
y.read(1);
99+
>y.read : Symbol(Constrained.read, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 24, 13))
100+
>y : Symbol(y, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 28, 13))
101+
>read : Symbol(Constrained.read, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 24, 13))
102+
103+
y.read("foo");
104+
>y.read : Symbol(Constrained.read, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 24, 13))
105+
>y : Symbol(y, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 28, 13))
106+
>read : Symbol(Constrained.read, Decl(inferInstanceTypeArgumentsAsConstraint.ts, 24, 13))
77107
}
78108

tests/baselines/reference/inferInstanceTypeArgumentsAsConstraint.types

+36
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ class Unconstrained<T> {
33
>Unconstrained : Unconstrained<T>
44

55
value: T;
6+
>value : T
7+
8+
read: (value: T) => void;
9+
>read : (value: T) => void
610
>value : T
711
}
812

@@ -64,12 +68,30 @@ if (x instanceof Unconstrained) {
6468
>x : Unconstrained<unknown>
6569
>value : number
6670
}
71+
72+
x.read(1);
73+
>x.read(1) : void
74+
>x.read : (value: unknown) => void
75+
>x : Unconstrained<unknown>
76+
>read : (value: unknown) => void
77+
>1 : 1
78+
79+
x.read("foo");
80+
>x.read("foo") : void
81+
>x.read : (value: unknown) => void
82+
>x : Unconstrained<unknown>
83+
>read : (value: unknown) => void
84+
>"foo" : "foo"
6785
}
6886

6987
class Constrained<T extends number> {
7088
>Constrained : Constrained<T>
7189

7290
value: T;
91+
>value : T
92+
93+
read: (value: T) => void;
94+
>read : (value: T) => void
7395
>value : T
7496
}
7597

@@ -86,5 +108,19 @@ if (y instanceof Constrained) {
86108
>y.value : number
87109
>y : Constrained<number>
88110
>value : number
111+
112+
y.read(1);
113+
>y.read(1) : void
114+
>y.read : (value: number) => void
115+
>y : Constrained<number>
116+
>read : (value: number) => void
117+
>1 : 1
118+
119+
y.read("foo");
120+
>y.read("foo") : void
121+
>y.read : (value: number) => void
122+
>y : Constrained<number>
123+
>read : (value: number) => void
124+
>"foo" : "foo"
89125
}
90126

0 commit comments

Comments
 (0)