Skip to content

Commit bd40583

Browse files
authored
Merge pull request microsoft#26698 from Microsoft/indexedAccessConstraints
Improve indexed access type relations
2 parents 7223945 + d369cec commit bd40583

File tree

5 files changed

+149
-13
lines changed

5 files changed

+149
-13
lines changed

src/compiler/checker.ts

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6905,10 +6905,15 @@ namespace ts {
69056905
}
69066906

69076907
function getConstraintOfIndexedAccess(type: IndexedAccessType) {
6908-
const objectType = getBaseConstraintOfType(type.objectType) || type.objectType;
6909-
const indexType = getBaseConstraintOfType(type.indexType) || type.indexType;
6910-
const constraint = !isGenericObjectType(objectType) && !isGenericIndexType(indexType) ? getIndexedAccessType(objectType, indexType, /*accessNode*/ undefined, errorType) : undefined;
6911-
return constraint && constraint !== errorType ? constraint : undefined;
6908+
const objectType = getConstraintOfType(type.objectType) || type.objectType;
6909+
if (objectType !== type.objectType) {
6910+
const constraint = getIndexedAccessType(objectType, type.indexType, /*accessNode*/ undefined, errorType);
6911+
if (constraint && constraint !== errorType) {
6912+
return constraint;
6913+
}
6914+
}
6915+
const baseConstraint = getBaseConstraintOfType(type);
6916+
return baseConstraint && baseConstraint !== type ? baseConstraint : undefined;
69126917
}
69136918

69146919
function getDefaultConstraintOfConditionalType(type: ConditionalType) {
@@ -7080,9 +7085,6 @@ namespace ts {
70807085
if (t.flags & TypeFlags.Substitution) {
70817086
return getBaseConstraint((<SubstitutionType>t).substitute);
70827087
}
7083-
if (isGenericMappedType(t)) {
7084-
return emptyObjectType;
7085-
}
70867088
return t;
70877089
}
70887090
}
@@ -11648,12 +11650,13 @@ namespace ts {
1164811650
}
1164911651
}
1165011652
else if (target.flags & TypeFlags.IndexedAccess) {
11651-
// A type S is related to a type T[K] if S is related to C, where C is the
11652-
// constraint of T[K]
11653-
const constraint = getConstraintForRelation(target);
11654-
if (constraint) {
11655-
if (result = isRelatedTo(source, constraint, reportErrors)) {
11656-
return result;
11653+
// A type S is related to a type T[K] if S is related to C, where C is the base constraint of T[K]
11654+
if (relation !== identityRelation) {
11655+
const constraint = getBaseConstraintOfType(target);
11656+
if (constraint && constraint !== target) {
11657+
if (result = isRelatedTo(source, constraint, reportErrors)) {
11658+
return result;
11659+
}
1165711660
}
1165811661
}
1165911662
}

tests/baselines/reference/keyofAndIndexedAccess.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,20 @@ function ff2<V extends string, T extends string>(dd: DictDict<V, T>, k1: V, k2:
649649
const d: Dict<T> = dd[k1];
650650
return d[k2];
651651
}
652+
653+
// Repro from #26409
654+
655+
const cf1 = <T extends { [P in K]: string; } & { cool: string; }, K extends keyof T>(t: T, k: K) =>
656+
{
657+
const s: string = t[k];
658+
t.cool;
659+
};
660+
661+
const cf2 = <T extends { [P in K | "cool"]: string; }, K extends keyof T>(t: T, k: K) =>
662+
{
663+
const s: string = t[k];
664+
t.cool;
665+
};
652666

653667

654668
//// [keyofAndIndexedAccess.js]
@@ -1078,6 +1092,15 @@ function ff2(dd, k1, k2) {
10781092
var d = dd[k1];
10791093
return d[k2];
10801094
}
1095+
// Repro from #26409
1096+
var cf1 = function (t, k) {
1097+
var s = t[k];
1098+
t.cool;
1099+
};
1100+
var cf2 = function (t, k) {
1101+
var s = t[k];
1102+
t.cool;
1103+
};
10811104

10821105

10831106
//// [keyofAndIndexedAccess.d.ts]
@@ -1413,3 +1436,7 @@ declare type DictDict<V extends string, T extends string> = {
14131436
};
14141437
declare function ff1<V extends string, T extends string>(dd: DictDict<V, T>, k1: V, k2: T): number;
14151438
declare function ff2<V extends string, T extends string>(dd: DictDict<V, T>, k1: V, k2: T): number;
1439+
declare const cf1: <T extends { [P in K]: string; } & {
1440+
cool: string;
1441+
}, K extends keyof T>(t: T, k: K) => void;
1442+
declare const cf2: <T extends { [P in K | "cool"]: string; }, K extends keyof T>(t: T, k: K) => void;

tests/baselines/reference/keyofAndIndexedAccess.symbols

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2319,3 +2319,54 @@ function ff2<V extends string, T extends string>(dd: DictDict<V, T>, k1: V, k2:
23192319
>k2 : Symbol(k2, Decl(keyofAndIndexedAccess.ts, 646, 75))
23202320
}
23212321

2322+
// Repro from #26409
2323+
2324+
const cf1 = <T extends { [P in K]: string; } & { cool: string; }, K extends keyof T>(t: T, k: K) =>
2325+
>cf1 : Symbol(cf1, Decl(keyofAndIndexedAccess.ts, 653, 5))
2326+
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 653, 13))
2327+
>P : Symbol(P, Decl(keyofAndIndexedAccess.ts, 653, 26))
2328+
>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 653, 65))
2329+
>cool : Symbol(cool, Decl(keyofAndIndexedAccess.ts, 653, 48))
2330+
>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 653, 65))
2331+
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 653, 13))
2332+
>t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 653, 85))
2333+
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 653, 13))
2334+
>k : Symbol(k, Decl(keyofAndIndexedAccess.ts, 653, 90))
2335+
>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 653, 65))
2336+
{
2337+
const s: string = t[k];
2338+
>s : Symbol(s, Decl(keyofAndIndexedAccess.ts, 655, 9))
2339+
>t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 653, 85))
2340+
>k : Symbol(k, Decl(keyofAndIndexedAccess.ts, 653, 90))
2341+
2342+
t.cool;
2343+
>t.cool : Symbol(cool, Decl(keyofAndIndexedAccess.ts, 653, 48))
2344+
>t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 653, 85))
2345+
>cool : Symbol(cool, Decl(keyofAndIndexedAccess.ts, 653, 48))
2346+
2347+
};
2348+
2349+
const cf2 = <T extends { [P in K | "cool"]: string; }, K extends keyof T>(t: T, k: K) =>
2350+
>cf2 : Symbol(cf2, Decl(keyofAndIndexedAccess.ts, 659, 5))
2351+
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 659, 13))
2352+
>P : Symbol(P, Decl(keyofAndIndexedAccess.ts, 659, 26))
2353+
>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 659, 54))
2354+
>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 659, 54))
2355+
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 659, 13))
2356+
>t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 659, 74))
2357+
>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 659, 13))
2358+
>k : Symbol(k, Decl(keyofAndIndexedAccess.ts, 659, 79))
2359+
>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 659, 54))
2360+
{
2361+
const s: string = t[k];
2362+
>s : Symbol(s, Decl(keyofAndIndexedAccess.ts, 661, 9))
2363+
>t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 659, 74))
2364+
>k : Symbol(k, Decl(keyofAndIndexedAccess.ts, 659, 79))
2365+
2366+
t.cool;
2367+
>t.cool : Symbol(cool)
2368+
>t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 659, 74))
2369+
>cool : Symbol(cool)
2370+
2371+
};
2372+

tests/baselines/reference/keyofAndIndexedAccess.types

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2184,3 +2184,44 @@ function ff2<V extends string, T extends string>(dd: DictDict<V, T>, k1: V, k2:
21842184
>k2 : T
21852185
}
21862186

2187+
// Repro from #26409
2188+
2189+
const cf1 = <T extends { [P in K]: string; } & { cool: string; }, K extends keyof T>(t: T, k: K) =>
2190+
>cf1 : <T extends { [P in K]: string; } & { cool: string; }, K extends keyof T>(t: T, k: K) => void
2191+
><T extends { [P in K]: string; } & { cool: string; }, K extends keyof T>(t: T, k: K) =>{ const s: string = t[k]; t.cool;} : <T extends { [P in K]: string; } & { cool: string; }, K extends keyof T>(t: T, k: K) => void
2192+
>cool : string
2193+
>t : T
2194+
>k : K
2195+
{
2196+
const s: string = t[k];
2197+
>s : string
2198+
>t[k] : T[K]
2199+
>t : T
2200+
>k : K
2201+
2202+
t.cool;
2203+
>t.cool : string
2204+
>t : T
2205+
>cool : string
2206+
2207+
};
2208+
2209+
const cf2 = <T extends { [P in K | "cool"]: string; }, K extends keyof T>(t: T, k: K) =>
2210+
>cf2 : <T extends { [P in K | "cool"]: string; }, K extends keyof T>(t: T, k: K) => void
2211+
><T extends { [P in K | "cool"]: string; }, K extends keyof T>(t: T, k: K) =>{ const s: string = t[k]; t.cool;} : <T extends { [P in K | "cool"]: string; }, K extends keyof T>(t: T, k: K) => void
2212+
>t : T
2213+
>k : K
2214+
{
2215+
const s: string = t[k];
2216+
>s : string
2217+
>t[k] : T[K]
2218+
>t : T
2219+
>k : K
2220+
2221+
t.cool;
2222+
>t.cool : string
2223+
>t : T
2224+
>cool : string
2225+
2226+
};
2227+

tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,3 +651,17 @@ function ff2<V extends string, T extends string>(dd: DictDict<V, T>, k1: V, k2:
651651
const d: Dict<T> = dd[k1];
652652
return d[k2];
653653
}
654+
655+
// Repro from #26409
656+
657+
const cf1 = <T extends { [P in K]: string; } & { cool: string; }, K extends keyof T>(t: T, k: K) =>
658+
{
659+
const s: string = t[k];
660+
t.cool;
661+
};
662+
663+
const cf2 = <T extends { [P in K | "cool"]: string; }, K extends keyof T>(t: T, k: K) =>
664+
{
665+
const s: string = t[k];
666+
t.cool;
667+
};

0 commit comments

Comments
 (0)