Skip to content

Commit 33d20e9

Browse files
authored
Merge pull request #23768 from Microsoft/fixIndexedAccessAssignability
Fix assignability of unconstrained T[K]
2 parents 732661c + f46040b commit 33d20e9

File tree

5 files changed

+856
-519
lines changed

5 files changed

+856
-519
lines changed

src/compiler/checker.ts

+11-22
Original file line numberDiff line numberDiff line change
@@ -10670,23 +10670,8 @@ namespace ts {
1067010670
}
1067110671
}
1067210672

10673-
if (source.flags & TypeFlags.TypeParameter) {
10674-
let constraint = getConstraintForRelation(<TypeParameter>source);
10675-
// A type parameter with no constraint is not related to the non-primitive object type.
10676-
if (constraint || !(target.flags & TypeFlags.NonPrimitive)) {
10677-
if (!constraint || constraint.flags & TypeFlags.Any) {
10678-
constraint = emptyObjectType;
10679-
}
10680-
// Report constraint errors only if the constraint is not the empty object type
10681-
const reportConstraintErrors = reportErrors && constraint !== emptyObjectType;
10682-
if (result = isRelatedTo(constraint, target, reportConstraintErrors)) {
10683-
errorInfo = saveErrorInfo;
10684-
return result;
10685-
}
10686-
}
10687-
}
10688-
else if (source.flags & TypeFlags.IndexedAccess) {
10689-
if (target.flags & TypeFlags.IndexedAccess) {
10673+
if (source.flags & TypeFlags.TypeVariable) {
10674+
if (source.flags & TypeFlags.IndexedAccess && target.flags & TypeFlags.IndexedAccess) {
1069010675
// A type S[K] is related to a type T[J] if S is related to T and K is related to J.
1069110676
if (result = isRelatedTo((<IndexedAccessType>source).objectType, (<IndexedAccessType>target).objectType, reportErrors)) {
1069210677
result &= isRelatedTo((<IndexedAccessType>source).indexType, (<IndexedAccessType>target).indexType, reportErrors);
@@ -10696,11 +10681,15 @@ namespace ts {
1069610681
return result;
1069710682
}
1069810683
}
10699-
// A type S[K] is related to a type T if C is related to T, where C is the
10700-
// constraint of S[K].
10701-
const constraint = getConstraintForRelation(<IndexedAccessType>source);
10702-
if (constraint) {
10703-
if (result = isRelatedTo(constraint, target, reportErrors)) {
10684+
let constraint = getConstraintForRelation(<TypeParameter>source);
10685+
// A type variable with no constraint is not related to the non-primitive object type.
10686+
if (constraint || !(target.flags & TypeFlags.NonPrimitive)) {
10687+
if (!constraint || constraint.flags & TypeFlags.Any) {
10688+
constraint = emptyObjectType;
10689+
}
10690+
// Report constraint errors only if the constraint is not the empty object type
10691+
const reportConstraintErrors = reportErrors && constraint !== emptyObjectType;
10692+
if (result = isRelatedTo(constraint, target, reportConstraintErrors)) {
1070410693
errorInfo = saveErrorInfo;
1070510694
return result;
1070610695
}

tests/baselines/reference/keyofAndIndexedAccess.js

+70
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,20 @@ function f90<T extends S2, K extends keyof S2>(x1: S2[keyof S2], x2: T[keyof S2]
319319
x4.length;
320320
}
321321

322+
function f91<T, K extends keyof T>(x: T, y: T[keyof T], z: T[K]) {
323+
let a: {};
324+
a = x;
325+
a = y;
326+
a = z;
327+
}
328+
329+
function f92<T, K extends keyof T>(x: T, y: T[keyof T], z: T[K]) {
330+
let a: {} | null | undefined;
331+
a = x;
332+
a = y;
333+
a = z;
334+
}
335+
322336
// Repros from #12011
323337

324338
class Base {
@@ -592,6 +606,27 @@ type DynamicDBRecord<Flag extends string> = ({ dynamicField: number } | { dynami
592606
function getFlagsFromDynamicRecord<Flag extends string>(record: DynamicDBRecord<Flag>, flags: Flag[]) {
593607
return record[flags[0]];
594608
}
609+
610+
// Repro from #21368
611+
612+
interface I {
613+
foo: string;
614+
}
615+
616+
declare function take<T>(p: T): void;
617+
618+
function fn<T extends I, K extends keyof T>(o: T, k: K) {
619+
take<{} | null | undefined>(o[k]);
620+
take<any>(o[k]);
621+
}
622+
623+
// Repro from #23133
624+
625+
class Unbounded<T> {
626+
foo(x: T[keyof T]) {
627+
let y: {} | undefined | null = x;
628+
}
629+
}
595630

596631

597632
//// [keyofAndIndexedAccess.js]
@@ -830,6 +865,18 @@ function f90(x1, x2, x3, x4) {
830865
x3.length;
831866
x4.length;
832867
}
868+
function f91(x, y, z) {
869+
var a;
870+
a = x;
871+
a = y;
872+
a = z;
873+
}
874+
function f92(x, y, z) {
875+
var a;
876+
a = x;
877+
a = y;
878+
a = z;
879+
}
833880
// Repros from #12011
834881
var Base = /** @class */ (function () {
835882
function Base() {
@@ -986,6 +1033,19 @@ function getFlagsFromSimpleRecord(record, flags) {
9861033
function getFlagsFromDynamicRecord(record, flags) {
9871034
return record[flags[0]];
9881035
}
1036+
function fn(o, k) {
1037+
take(o[k]);
1038+
take(o[k]);
1039+
}
1040+
// Repro from #23133
1041+
var Unbounded = /** @class */ (function () {
1042+
function Unbounded() {
1043+
}
1044+
Unbounded.prototype.foo = function (x) {
1045+
var y = x;
1046+
};
1047+
return Unbounded;
1048+
}());
9891049

9901050

9911051
//// [keyofAndIndexedAccess.d.ts]
@@ -1126,6 +1186,8 @@ declare type S2 = {
11261186
b: string;
11271187
};
11281188
declare function f90<T extends S2, K extends keyof S2>(x1: S2[keyof S2], x2: T[keyof S2], x3: S2[K], x4: T[K]): void;
1189+
declare function f91<T, K extends keyof T>(x: T, y: T[keyof T], z: T[K]): void;
1190+
declare function f92<T, K extends keyof T>(x: T, y: T[keyof T], z: T[K]): void;
11291191
declare class Base {
11301192
get<K extends keyof this>(prop: K): this[K];
11311193
set<K extends keyof this>(prop: K, value: this[K]): void;
@@ -1298,3 +1360,11 @@ declare type DynamicDBRecord<Flag extends string> = ({
12981360
dynamicField: string;
12991361
}) & DBBoolTable<Flag>;
13001362
declare function getFlagsFromDynamicRecord<Flag extends string>(record: DynamicDBRecord<Flag>, flags: Flag[]): DynamicDBRecord<Flag>[Flag];
1363+
interface I {
1364+
foo: string;
1365+
}
1366+
declare function take<T>(p: T): void;
1367+
declare function fn<T extends I, K extends keyof T>(o: T, k: K): void;
1368+
declare class Unbounded<T> {
1369+
foo(x: T[keyof T]): void;
1370+
}

0 commit comments

Comments
 (0)