Skip to content

Commit 0715fe5

Browse files
Better compatibility error for indexed access type (microsoft#51228)
1 parent 1da4725 commit 0715fe5

11 files changed

+219
-34
lines changed

src/compiler/checker.ts

+24-19
Original file line numberDiff line numberDiff line change
@@ -20204,26 +20204,31 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2020420204
generalizedSourceType = getTypeNameForErrorDisplay(generalizedSource);
2020520205
}
2020620206

20207-
if (target.flags & TypeFlags.TypeParameter && target !== markerSuperTypeForCheck && target !== markerSubTypeForCheck) {
20208-
const constraint = getBaseConstraintOfType(target);
20209-
let needsOriginalSource;
20210-
if (constraint && (isTypeAssignableTo(generalizedSource, constraint) || (needsOriginalSource = isTypeAssignableTo(source, constraint)))) {
20211-
reportError(
20212-
Diagnostics._0_is_assignable_to_the_constraint_of_type_1_but_1_could_be_instantiated_with_a_different_subtype_of_constraint_2,
20213-
needsOriginalSource ? sourceType : generalizedSourceType,
20214-
targetType,
20215-
typeToString(constraint),
20216-
);
20217-
}
20218-
else {
20219-
errorInfo = undefined;
20220-
reportError(
20221-
Diagnostics._0_could_be_instantiated_with_an_arbitrary_type_which_could_be_unrelated_to_1,
20222-
targetType,
20223-
generalizedSourceType
20224-
);
20207+
// If `target` is of indexed access type (And `source` it is not), we use the object type of `target` for better error reporting
20208+
const targetFlags = target.flags & TypeFlags.IndexedAccess && !(source.flags & TypeFlags.IndexedAccess) ?
20209+
(target as IndexedAccessType).objectType.flags :
20210+
target.flags;
20211+
20212+
if (targetFlags & TypeFlags.TypeParameter && target !== markerSuperTypeForCheck && target !== markerSubTypeForCheck) {
20213+
const constraint = getBaseConstraintOfType(target);
20214+
let needsOriginalSource;
20215+
if (constraint && (isTypeAssignableTo(generalizedSource, constraint) || (needsOriginalSource = isTypeAssignableTo(source, constraint)))) {
20216+
reportError(
20217+
Diagnostics._0_is_assignable_to_the_constraint_of_type_1_but_1_could_be_instantiated_with_a_different_subtype_of_constraint_2,
20218+
needsOriginalSource ? sourceType : generalizedSourceType,
20219+
targetType,
20220+
typeToString(constraint),
20221+
);
20222+
}
20223+
else {
20224+
errorInfo = undefined;
20225+
reportError(
20226+
Diagnostics._0_could_be_instantiated_with_an_arbitrary_type_which_could_be_unrelated_to_1,
20227+
targetType,
20228+
generalizedSourceType
20229+
);
20230+
}
2022520231
}
20226-
}
2022720232

2022820233
if (!message) {
2022920234
if (relation === comparableRelation) {

tests/baselines/reference/conditionalTypes1.errors.txt

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(17,5): error TS23
1111
tests/cases/conformance/types/conditional/conditionalTypes1.ts(24,5): error TS2322: Type 'T[keyof T] | undefined' is not assignable to type 'NonNullable<Partial<T>[keyof T]>'.
1212
Type 'undefined' is not assignable to type 'T[keyof T] & {}'.
1313
Type 'undefined' is not assignable to type 'T[keyof T]'.
14+
'T[keyof T]' could be instantiated with an arbitrary type which could be unrelated to 'undefined'.
1415
tests/cases/conformance/types/conditional/conditionalTypes1.ts(29,5): error TS2322: Type 'T["x"]' is not assignable to type 'NonNullable<T["x"]>'.
1516
Type 'string | undefined' is not assignable to type 'NonNullable<T["x"]>'.
1617
Type 'undefined' is not assignable to type 'NonNullable<T["x"]>'.
@@ -110,6 +111,7 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(288,43): error TS
110111
!!! error TS2322: Type 'T[keyof T] | undefined' is not assignable to type 'NonNullable<Partial<T>[keyof T]>'.
111112
!!! error TS2322: Type 'undefined' is not assignable to type 'T[keyof T] & {}'.
112113
!!! error TS2322: Type 'undefined' is not assignable to type 'T[keyof T]'.
114+
!!! error TS2322: 'T[keyof T]' could be instantiated with an arbitrary type which could be unrelated to 'undefined'.
113115
}
114116

115117
function f4<T extends { x: string | undefined }>(x: T["x"], y: NonNullable<T["x"]>) {

tests/baselines/reference/indexedAccessRelation.errors.txt

+2-4
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ tests/cases/compiler/indexedAccessRelation.ts(16,23): error TS2345: Argument of
33
Type 'T' is not assignable to type 'S["a"] & T'.
44
Type 'Foo' is not assignable to type 'S["a"] & T'.
55
Type 'Foo' is not assignable to type 'S["a"]'.
6-
Type 'T' is not assignable to type 'S["a"]'.
7-
Type 'Foo' is not assignable to type 'S["a"]'.
6+
'S["a"]' could be instantiated with an arbitrary type which could be unrelated to 'Foo'.
87

98

109
==== tests/cases/compiler/indexedAccessRelation.ts (1 errors) ====
@@ -30,8 +29,7 @@ tests/cases/compiler/indexedAccessRelation.ts(16,23): error TS2345: Argument of
3029
!!! error TS2345: Type 'T' is not assignable to type 'S["a"] & T'.
3130
!!! error TS2345: Type 'Foo' is not assignable to type 'S["a"] & T'.
3231
!!! error TS2345: Type 'Foo' is not assignable to type 'S["a"]'.
33-
!!! error TS2345: Type 'T' is not assignable to type 'S["a"]'.
34-
!!! error TS2345: Type 'Foo' is not assignable to type 'S["a"]'.
32+
!!! error TS2345: 'S["a"]' could be instantiated with an arbitrary type which could be unrelated to 'Foo'.
3533
}
3634
}
3735

tests/baselines/reference/keyofAndIndexedAccess2.errors.txt

+10
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,22 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(19,5): error TS232
1313
'{ [key: string]: number; }' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '{ [key: string]: number; }'.
1414
tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(26,7): error TS2339: Property 'x' does not exist on type 'T'.
1515
tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(27,5): error TS2322: Type 'number' is not assignable to type 'T[keyof T]'.
16+
'number' is assignable to the constraint of type 'T[keyof T]', but 'T[keyof T]' could be instantiated with a different subtype of constraint 'number'.
1617
tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(31,5): error TS2322: Type '{ [key: string]: number; }' is not assignable to type '{ [P in K]: number; }'.
1718
tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(38,5): error TS2322: Type '{ [x: string]: number; }' is not assignable to type '{ [P in K]: number; }'.
1819
tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(50,3): error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Item'.
1920
No index signature with a parameter of type 'string' was found on type 'Item'.
2021
tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(51,3): error TS2322: Type 'number' is not assignable to type 'never'.
2122
tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(52,3): error TS2322: Type 'number' is not assignable to type 'T[keyof T]'.
23+
'T[keyof T]' could be instantiated with an arbitrary type which could be unrelated to 'number'.
2224
tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(53,3): error TS2322: Type 'number' is not assignable to type 'T[K]'.
25+
'T[K]' could be instantiated with an arbitrary type which could be unrelated to 'number'.
2326
tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(65,7): error TS2339: Property 'foo' does not exist on type 'T'.
2427
tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(66,3): error TS2536: Type 'string' cannot be used to index type 'T'.
2528
tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(67,3): error TS2322: Type 'number' is not assignable to type 'T[keyof T]'.
29+
'number' is assignable to the constraint of type 'T[keyof T]', but 'T[keyof T]' could be instantiated with a different subtype of constraint 'number'.
2630
tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(68,3): error TS2322: Type 'number' is not assignable to type 'T[K]'.
31+
'number' is assignable to the constraint of type 'T[K]', but 'T[K]' could be instantiated with a different subtype of constraint 'number'.
2732
tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(108,5): error TS2322: Type '123' is not assignable to type 'Type[K]'.
2833
Type 'number' is not assignable to type 'never'.
2934

@@ -83,6 +88,7 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(108,5): error TS23
8388
c[k] = 1; // Error, cannot write to index signature through constraint
8489
~~~~
8590
!!! error TS2322: Type 'number' is not assignable to type 'T[keyof T]'.
91+
!!! error TS2322: 'number' is assignable to the constraint of type 'T[keyof T]', but 'T[keyof T]' could be instantiated with a different subtype of constraint 'number'.
8692
}
8793

8894
function f3<K extends string>(a: { [P in K]: number }, b: { [key: string]: number }, k: K) {
@@ -119,9 +125,11 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(108,5): error TS23
119125
obj[k3] = 123; // Error
120126
~~~~~~~
121127
!!! error TS2322: Type 'number' is not assignable to type 'T[keyof T]'.
128+
!!! error TS2322: 'T[keyof T]' could be instantiated with an arbitrary type which could be unrelated to 'number'.
122129
obj[k4] = 123; // Error
123130
~~~~~~~
124131
!!! error TS2322: Type 'number' is not assignable to type 'T[K]'.
132+
!!! error TS2322: 'T[K]' could be instantiated with an arbitrary type which could be unrelated to 'number'.
125133
}
126134

127135
type Dict = Record<string, number>;
@@ -142,9 +150,11 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccess2.ts(108,5): error TS23
142150
obj[k2] = 123; // Error
143151
~~~~~~~
144152
!!! error TS2322: Type 'number' is not assignable to type 'T[keyof T]'.
153+
!!! error TS2322: 'number' is assignable to the constraint of type 'T[keyof T]', but 'T[keyof T]' could be instantiated with a different subtype of constraint 'number'.
145154
obj[k3] = 123; // Error
146155
~~~~~~~
147156
!!! error TS2322: Type 'number' is not assignable to type 'T[K]'.
157+
!!! error TS2322: 'number' is assignable to the constraint of type 'T[K]', but 'T[K]' could be instantiated with a different subtype of constraint 'number'.
148158
}
149159

150160
// Repro from #27895

tests/baselines/reference/keyofAndIndexedAccessErrors.errors.txt

+28-1
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,16 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(117,5): error
6262
tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(122,5): error TS2322: Type 'number' is not assignable to type 'keyof T'.
6363
tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(123,5): error TS2322: Type 'string' is not assignable to type 'keyof T'.
6464
tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(140,5): error TS2322: Type 'number' is not assignable to type 'T[K]'.
65+
'number' is assignable to the constraint of type 'T[K]', but 'T[K]' could be instantiated with a different subtype of constraint 'any'.
6566
tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(141,5): error TS2322: Type 'string' is not assignable to type 'T[K]'.
67+
'string' is assignable to the constraint of type 'T[K]', but 'T[K]' could be instantiated with a different subtype of constraint 'any'.
6668
tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(142,5): error TS2322: Type 'number[]' is not assignable to type 'T[K]'.
69+
'number[]' is assignable to the constraint of type 'T[K]', but 'T[K]' could be instantiated with a different subtype of constraint 'any'.
70+
tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(165,5): error TS2322: Type 'number' is not assignable to type 'T[keyof T]'.
71+
'number' is assignable to the constraint of type 'T[keyof T]', but 'T[keyof T]' could be instantiated with a different subtype of constraint 'number'.
6772

6873

69-
==== tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts (40 errors) ====
74+
==== tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts (41 errors) ====
7075
class Shape {
7176
name: string;
7277
width: number;
@@ -312,12 +317,15 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(142,5): error
312317
t[k] = 42; // Error
313318
~~~~
314319
!!! error TS2322: Type 'number' is not assignable to type 'T[K]'.
320+
!!! error TS2322: 'number' is assignable to the constraint of type 'T[K]', but 'T[K]' could be instantiated with a different subtype of constraint 'any'.
315321
t[k] = "hello"; // Error
316322
~~~~
317323
!!! error TS2322: Type 'string' is not assignable to type 'T[K]'.
324+
!!! error TS2322: 'string' is assignable to the constraint of type 'T[K]', but 'T[K]' could be instantiated with a different subtype of constraint 'any'.
318325
t[k] = [10, 20]; // Error
319326
~~~~
320327
!!! error TS2322: Type 'number[]' is not assignable to type 'T[K]'.
328+
!!! error TS2322: 'number[]' is assignable to the constraint of type 'T[K]', but 'T[K]' could be instantiated with a different subtype of constraint 'any'.
321329
}
322330

323331
// Repro from #28839
@@ -329,4 +337,23 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(142,5): error
329337
function f31<T, K extends keyof T>() {
330338
let x: Partial<Partial<Partial<Partial<Partial<Partial<Partial<Record<keyof T, string>>>>>>>>[K] = "hello";
331339
}
340+
341+
// Repro from #51069
342+
343+
class Test<T extends Record<string, number>> {
344+
testy: T;
345+
346+
constructor(t: T) {
347+
this.testy = t;
348+
}
349+
350+
public t(key: keyof T): number {
351+
this.testy[key] += 1; // Error
352+
~~~~~~~~~~~~~~~
353+
!!! error TS2322: Type 'number' is not assignable to type 'T[keyof T]'.
354+
!!! error TS2322: 'number' is assignable to the constraint of type 'T[keyof T]', but 'T[keyof T]' could be instantiated with a different subtype of constraint 'number'.
355+
356+
return this.testy[key];
357+
}
358+
}
332359

tests/baselines/reference/keyofAndIndexedAccessErrors.js

+27
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,22 @@ function f30<T, K extends keyof T>() {
152152
function f31<T, K extends keyof T>() {
153153
let x: Partial<Partial<Partial<Partial<Partial<Partial<Partial<Record<keyof T, string>>>>>>>>[K] = "hello";
154154
}
155+
156+
// Repro from #51069
157+
158+
class Test<T extends Record<string, number>> {
159+
testy: T;
160+
161+
constructor(t: T) {
162+
this.testy = t;
163+
}
164+
165+
public t(key: keyof T): number {
166+
this.testy[key] += 1; // Error
167+
168+
return this.testy[key];
169+
}
170+
}
155171

156172

157173
//// [keyofAndIndexedAccessErrors.js]
@@ -232,3 +248,14 @@ function f30() {
232248
function f31() {
233249
var x = "hello";
234250
}
251+
// Repro from #51069
252+
var Test = /** @class */ (function () {
253+
function Test(t) {
254+
this.testy = t;
255+
}
256+
Test.prototype.t = function (key) {
257+
this.testy[key] += 1; // Error
258+
return this.testy[key];
259+
};
260+
return Test;
261+
}());

tests/baselines/reference/keyofAndIndexedAccessErrors.symbols

+41
Original file line numberDiff line numberDiff line change
@@ -523,3 +523,44 @@ function f31<T, K extends keyof T>() {
523523
>K : Symbol(K, Decl(keyofAndIndexedAccessErrors.ts, 150, 15))
524524
}
525525

526+
// Repro from #51069
527+
528+
class Test<T extends Record<string, number>> {
529+
>Test : Symbol(Test, Decl(keyofAndIndexedAccessErrors.ts, 152, 1))
530+
>T : Symbol(T, Decl(keyofAndIndexedAccessErrors.ts, 156, 11))
531+
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
532+
533+
testy: T;
534+
>testy : Symbol(Test.testy, Decl(keyofAndIndexedAccessErrors.ts, 156, 46))
535+
>T : Symbol(T, Decl(keyofAndIndexedAccessErrors.ts, 156, 11))
536+
537+
constructor(t: T) {
538+
>t : Symbol(t, Decl(keyofAndIndexedAccessErrors.ts, 159, 14))
539+
>T : Symbol(T, Decl(keyofAndIndexedAccessErrors.ts, 156, 11))
540+
541+
this.testy = t;
542+
>this.testy : Symbol(Test.testy, Decl(keyofAndIndexedAccessErrors.ts, 156, 46))
543+
>this : Symbol(Test, Decl(keyofAndIndexedAccessErrors.ts, 152, 1))
544+
>testy : Symbol(Test.testy, Decl(keyofAndIndexedAccessErrors.ts, 156, 46))
545+
>t : Symbol(t, Decl(keyofAndIndexedAccessErrors.ts, 159, 14))
546+
}
547+
548+
public t(key: keyof T): number {
549+
>t : Symbol(Test.t, Decl(keyofAndIndexedAccessErrors.ts, 161, 3))
550+
>key : Symbol(key, Decl(keyofAndIndexedAccessErrors.ts, 163, 11))
551+
>T : Symbol(T, Decl(keyofAndIndexedAccessErrors.ts, 156, 11))
552+
553+
this.testy[key] += 1; // Error
554+
>this.testy : Symbol(Test.testy, Decl(keyofAndIndexedAccessErrors.ts, 156, 46))
555+
>this : Symbol(Test, Decl(keyofAndIndexedAccessErrors.ts, 152, 1))
556+
>testy : Symbol(Test.testy, Decl(keyofAndIndexedAccessErrors.ts, 156, 46))
557+
>key : Symbol(key, Decl(keyofAndIndexedAccessErrors.ts, 163, 11))
558+
559+
return this.testy[key];
560+
>this.testy : Symbol(Test.testy, Decl(keyofAndIndexedAccessErrors.ts, 156, 46))
561+
>this : Symbol(Test, Decl(keyofAndIndexedAccessErrors.ts, 152, 1))
562+
>testy : Symbol(Test.testy, Decl(keyofAndIndexedAccessErrors.ts, 156, 46))
563+
>key : Symbol(key, Decl(keyofAndIndexedAccessErrors.ts, 163, 11))
564+
}
565+
}
566+

tests/baselines/reference/keyofAndIndexedAccessErrors.types

+41
Original file line numberDiff line numberDiff line change
@@ -483,3 +483,44 @@ function f31<T, K extends keyof T>() {
483483
>"hello" : "hello"
484484
}
485485

486+
// Repro from #51069
487+
488+
class Test<T extends Record<string, number>> {
489+
>Test : Test<T>
490+
491+
testy: T;
492+
>testy : T
493+
494+
constructor(t: T) {
495+
>t : T
496+
497+
this.testy = t;
498+
>this.testy = t : T
499+
>this.testy : T
500+
>this : this
501+
>testy : T
502+
>t : T
503+
}
504+
505+
public t(key: keyof T): number {
506+
>t : (key: keyof T) => number
507+
>key : keyof T
508+
509+
this.testy[key] += 1; // Error
510+
>this.testy[key] += 1 : number
511+
>this.testy[key] : T[keyof T]
512+
>this.testy : T
513+
>this : this
514+
>testy : T
515+
>key : keyof T
516+
>1 : 1
517+
518+
return this.testy[key];
519+
>this.testy[key] : T[keyof T]
520+
>this.testy : T
521+
>this : this
522+
>testy : T
523+
>key : keyof T
524+
}
525+
}
526+

0 commit comments

Comments
 (0)