diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 679cb79e0cf84..2d4239f578e93 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6905,10 +6905,15 @@ namespace ts { } function getConstraintOfIndexedAccess(type: IndexedAccessType) { - const objectType = getBaseConstraintOfType(type.objectType) || type.objectType; - const indexType = getBaseConstraintOfType(type.indexType) || type.indexType; - const constraint = !isGenericObjectType(objectType) && !isGenericIndexType(indexType) ? getIndexedAccessType(objectType, indexType, /*accessNode*/ undefined, errorType) : undefined; - return constraint && constraint !== errorType ? constraint : undefined; + const objectType = getConstraintOfType(type.objectType) || type.objectType; + if (objectType !== type.objectType) { + const constraint = getIndexedAccessType(objectType, type.indexType, /*accessNode*/ undefined, errorType); + if (constraint && constraint !== errorType) { + return constraint; + } + } + const baseConstraint = getBaseConstraintOfType(type); + return baseConstraint && baseConstraint !== type ? baseConstraint : undefined; } function getDefaultConstraintOfConditionalType(type: ConditionalType) { @@ -7080,9 +7085,6 @@ namespace ts { if (t.flags & TypeFlags.Substitution) { return getBaseConstraint((t).substitute); } - if (isGenericMappedType(t)) { - return emptyObjectType; - } return t; } } @@ -11648,12 +11650,13 @@ namespace ts { } } else if (target.flags & TypeFlags.IndexedAccess) { - // A type S is related to a type T[K] if S is related to C, where C is the - // constraint of T[K] - const constraint = getConstraintForRelation(target); - if (constraint) { - if (result = isRelatedTo(source, constraint, reportErrors)) { - return result; + // 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] + if (relation !== identityRelation) { + const constraint = getBaseConstraintOfType(target); + if (constraint && constraint !== target) { + if (result = isRelatedTo(source, constraint, reportErrors)) { + return result; + } } } } diff --git a/tests/baselines/reference/keyofAndIndexedAccess.js b/tests/baselines/reference/keyofAndIndexedAccess.js index cc0498fcfe262..873fa2a035a78 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess.js +++ b/tests/baselines/reference/keyofAndIndexedAccess.js @@ -649,6 +649,20 @@ function ff2(dd: DictDict, k1: V, k2: const d: Dict = dd[k1]; return d[k2]; } + +// Repro from #26409 + +const cf1 = (t: T, k: K) => +{ + const s: string = t[k]; + t.cool; +}; + +const cf2 = (t: T, k: K) => +{ + const s: string = t[k]; + t.cool; +}; //// [keyofAndIndexedAccess.js] @@ -1078,6 +1092,15 @@ function ff2(dd, k1, k2) { var d = dd[k1]; return d[k2]; } +// Repro from #26409 +var cf1 = function (t, k) { + var s = t[k]; + t.cool; +}; +var cf2 = function (t, k) { + var s = t[k]; + t.cool; +}; //// [keyofAndIndexedAccess.d.ts] @@ -1413,3 +1436,7 @@ declare type DictDict = { }; declare function ff1(dd: DictDict, k1: V, k2: T): number; declare function ff2(dd: DictDict, k1: V, k2: T): number; +declare const cf1: (t: T, k: K) => void; +declare const cf2: (t: T, k: K) => void; diff --git a/tests/baselines/reference/keyofAndIndexedAccess.symbols b/tests/baselines/reference/keyofAndIndexedAccess.symbols index c8bb9f14da746..15cc704c4817b 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess.symbols +++ b/tests/baselines/reference/keyofAndIndexedAccess.symbols @@ -2319,3 +2319,54 @@ function ff2(dd: DictDict, k1: V, k2: >k2 : Symbol(k2, Decl(keyofAndIndexedAccess.ts, 646, 75)) } +// Repro from #26409 + +const cf1 = (t: T, k: K) => +>cf1 : Symbol(cf1, Decl(keyofAndIndexedAccess.ts, 653, 5)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 653, 13)) +>P : Symbol(P, Decl(keyofAndIndexedAccess.ts, 653, 26)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 653, 65)) +>cool : Symbol(cool, Decl(keyofAndIndexedAccess.ts, 653, 48)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 653, 65)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 653, 13)) +>t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 653, 85)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 653, 13)) +>k : Symbol(k, Decl(keyofAndIndexedAccess.ts, 653, 90)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 653, 65)) +{ + const s: string = t[k]; +>s : Symbol(s, Decl(keyofAndIndexedAccess.ts, 655, 9)) +>t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 653, 85)) +>k : Symbol(k, Decl(keyofAndIndexedAccess.ts, 653, 90)) + + t.cool; +>t.cool : Symbol(cool, Decl(keyofAndIndexedAccess.ts, 653, 48)) +>t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 653, 85)) +>cool : Symbol(cool, Decl(keyofAndIndexedAccess.ts, 653, 48)) + +}; + +const cf2 = (t: T, k: K) => +>cf2 : Symbol(cf2, Decl(keyofAndIndexedAccess.ts, 659, 5)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 659, 13)) +>P : Symbol(P, Decl(keyofAndIndexedAccess.ts, 659, 26)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 659, 54)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 659, 54)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 659, 13)) +>t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 659, 74)) +>T : Symbol(T, Decl(keyofAndIndexedAccess.ts, 659, 13)) +>k : Symbol(k, Decl(keyofAndIndexedAccess.ts, 659, 79)) +>K : Symbol(K, Decl(keyofAndIndexedAccess.ts, 659, 54)) +{ + const s: string = t[k]; +>s : Symbol(s, Decl(keyofAndIndexedAccess.ts, 661, 9)) +>t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 659, 74)) +>k : Symbol(k, Decl(keyofAndIndexedAccess.ts, 659, 79)) + + t.cool; +>t.cool : Symbol(cool) +>t : Symbol(t, Decl(keyofAndIndexedAccess.ts, 659, 74)) +>cool : Symbol(cool) + +}; + diff --git a/tests/baselines/reference/keyofAndIndexedAccess.types b/tests/baselines/reference/keyofAndIndexedAccess.types index 3434d003d54d6..58fd74f66014a 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess.types +++ b/tests/baselines/reference/keyofAndIndexedAccess.types @@ -2184,3 +2184,44 @@ function ff2(dd: DictDict, k1: V, k2: >k2 : T } +// Repro from #26409 + +const cf1 = (t: T, k: K) => +>cf1 : (t: T, k: K) => void +>(t: T, k: K) =>{ const s: string = t[k]; t.cool;} : (t: T, k: K) => void +>cool : string +>t : T +>k : K +{ + const s: string = t[k]; +>s : string +>t[k] : T[K] +>t : T +>k : K + + t.cool; +>t.cool : string +>t : T +>cool : string + +}; + +const cf2 = (t: T, k: K) => +>cf2 : (t: T, k: K) => void +>(t: T, k: K) =>{ const s: string = t[k]; t.cool;} : (t: T, k: K) => void +>t : T +>k : K +{ + const s: string = t[k]; +>s : string +>t[k] : T[K] +>t : T +>k : K + + t.cool; +>t.cool : string +>t : T +>cool : string + +}; + diff --git a/tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts b/tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts index c76071f7d99da..7748240f80d60 100644 --- a/tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts +++ b/tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts @@ -651,3 +651,17 @@ function ff2(dd: DictDict, k1: V, k2: const d: Dict = dd[k1]; return d[k2]; } + +// Repro from #26409 + +const cf1 = (t: T, k: K) => +{ + const s: string = t[k]; + t.cool; +}; + +const cf2 = (t: T, k: K) => +{ + const s: string = t[k]; + t.cool; +};