diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 47ea66ff9af92..94a6629f37151 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -25051,7 +25051,7 @@ namespace ts { const substituteConstraints = !(checkMode && checkMode & CheckMode.Inferential) && someType(type, isGenericTypeWithUnionConstraint) && (isConstraintPosition(type, reference) || hasContextualTypeWithNoGenericTypes(reference, checkMode)); - return substituteConstraints ? mapType(type, t => t.flags & TypeFlags.Instantiable && !isMappedTypeGenericIndexedAccess(t) ? getBaseConstraintOrType(t) : t) : type; + return substituteConstraints ? mapType(type, t => t.flags & TypeFlags.Instantiable ? getBaseConstraintOrType(t) : t) : type; } function isExportOrExportExpression(location: Node) { diff --git a/tests/baselines/reference/correlatedUnions.js b/tests/baselines/reference/correlatedUnions.js index b42a48c68a0e2..f1e13f4417030 100644 --- a/tests/baselines/reference/correlatedUnions.js +++ b/tests/baselines/reference/correlatedUnions.js @@ -181,6 +181,34 @@ function f3(funcs: Funcs, key: K, arg: ArgMap[K]) { function f4(x: Funcs[keyof ArgMap], y: Funcs[K]) { x = y; } + +// Repro from #47890 + +interface MyObj { + someKey: { + name: string; + } + someOtherKey: { + name: number; + } +} + +const ref: MyObj = { + someKey: { name: "" }, + someOtherKey: { name: 42 } +}; + +function func(k: K): MyObj[K]['name'] | undefined { + const myObj: Partial[K] = ref[k]; + if (myObj) { + return myObj.name; + } + const myObj2: Partial[keyof MyObj] = ref[k]; + if (myObj2) { + return myObj2.name; + } + return undefined; +} //// [correlatedUnions.js] @@ -282,6 +310,21 @@ function f3(funcs, key, arg) { function f4(x, y) { x = y; } +var ref = { + someKey: { name: "" }, + someOtherKey: { name: 42 } +}; +function func(k) { + var myObj = ref[k]; + if (myObj) { + return myObj.name; + } + var myObj2 = ref[k]; + if (myObj2) { + return myObj2.name; + } + return undefined; +} //// [correlatedUnions.d.ts] @@ -398,3 +441,13 @@ declare function f1(funcs: Funcs, key: K, arg: ArgMap[K] declare function f2(funcs: Funcs, key: K, arg: ArgMap[K]): void; declare function f3(funcs: Funcs, key: K, arg: ArgMap[K]): void; declare function f4(x: Funcs[keyof ArgMap], y: Funcs[K]): void; +interface MyObj { + someKey: { + name: string; + }; + someOtherKey: { + name: number; + }; +} +declare const ref: MyObj; +declare function func(k: K): MyObj[K]['name'] | undefined; diff --git a/tests/baselines/reference/correlatedUnions.symbols b/tests/baselines/reference/correlatedUnions.symbols index 040c3983e95dd..16fa17e1a4f0e 100644 --- a/tests/baselines/reference/correlatedUnions.symbols +++ b/tests/baselines/reference/correlatedUnions.symbols @@ -675,3 +675,81 @@ function f4(x: Funcs[keyof ArgMap], y: Funcs[K]) { >y : Symbol(y, Decl(correlatedUnions.ts, 179, 59)) } +// Repro from #47890 + +interface MyObj { +>MyObj : Symbol(MyObj, Decl(correlatedUnions.ts, 181, 1)) + + someKey: { +>someKey : Symbol(MyObj.someKey, Decl(correlatedUnions.ts, 185, 17)) + + name: string; +>name : Symbol(name, Decl(correlatedUnions.ts, 186, 14)) + } + someOtherKey: { +>someOtherKey : Symbol(MyObj.someOtherKey, Decl(correlatedUnions.ts, 188, 5)) + + name: number; +>name : Symbol(name, Decl(correlatedUnions.ts, 189, 19)) + } +} + +const ref: MyObj = { +>ref : Symbol(ref, Decl(correlatedUnions.ts, 194, 5)) +>MyObj : Symbol(MyObj, Decl(correlatedUnions.ts, 181, 1)) + + someKey: { name: "" }, +>someKey : Symbol(someKey, Decl(correlatedUnions.ts, 194, 20)) +>name : Symbol(name, Decl(correlatedUnions.ts, 195, 14)) + + someOtherKey: { name: 42 } +>someOtherKey : Symbol(someOtherKey, Decl(correlatedUnions.ts, 195, 26)) +>name : Symbol(name, Decl(correlatedUnions.ts, 196, 19)) + +}; + +function func(k: K): MyObj[K]['name'] | undefined { +>func : Symbol(func, Decl(correlatedUnions.ts, 197, 2)) +>K : Symbol(K, Decl(correlatedUnions.ts, 199, 14)) +>MyObj : Symbol(MyObj, Decl(correlatedUnions.ts, 181, 1)) +>k : Symbol(k, Decl(correlatedUnions.ts, 199, 37)) +>K : Symbol(K, Decl(correlatedUnions.ts, 199, 14)) +>MyObj : Symbol(MyObj, Decl(correlatedUnions.ts, 181, 1)) +>K : Symbol(K, Decl(correlatedUnions.ts, 199, 14)) + + const myObj: Partial[K] = ref[k]; +>myObj : Symbol(myObj, Decl(correlatedUnions.ts, 200, 9)) +>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --)) +>MyObj : Symbol(MyObj, Decl(correlatedUnions.ts, 181, 1)) +>K : Symbol(K, Decl(correlatedUnions.ts, 199, 14)) +>ref : Symbol(ref, Decl(correlatedUnions.ts, 194, 5)) +>k : Symbol(k, Decl(correlatedUnions.ts, 199, 37)) + + if (myObj) { +>myObj : Symbol(myObj, Decl(correlatedUnions.ts, 200, 9)) + + return myObj.name; +>myObj.name : Symbol(name, Decl(correlatedUnions.ts, 186, 14), Decl(correlatedUnions.ts, 189, 19)) +>myObj : Symbol(myObj, Decl(correlatedUnions.ts, 200, 9)) +>name : Symbol(name, Decl(correlatedUnions.ts, 186, 14), Decl(correlatedUnions.ts, 189, 19)) + } + const myObj2: Partial[keyof MyObj] = ref[k]; +>myObj2 : Symbol(myObj2, Decl(correlatedUnions.ts, 204, 9)) +>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --)) +>MyObj : Symbol(MyObj, Decl(correlatedUnions.ts, 181, 1)) +>MyObj : Symbol(MyObj, Decl(correlatedUnions.ts, 181, 1)) +>ref : Symbol(ref, Decl(correlatedUnions.ts, 194, 5)) +>k : Symbol(k, Decl(correlatedUnions.ts, 199, 37)) + + if (myObj2) { +>myObj2 : Symbol(myObj2, Decl(correlatedUnions.ts, 204, 9)) + + return myObj2.name; +>myObj2.name : Symbol(name, Decl(correlatedUnions.ts, 186, 14), Decl(correlatedUnions.ts, 189, 19)) +>myObj2 : Symbol(myObj2, Decl(correlatedUnions.ts, 204, 9)) +>name : Symbol(name, Decl(correlatedUnions.ts, 186, 14), Decl(correlatedUnions.ts, 189, 19)) + } + return undefined; +>undefined : Symbol(undefined) +} + diff --git a/tests/baselines/reference/correlatedUnions.types b/tests/baselines/reference/correlatedUnions.types index ae14133757619..3a4d950070704 100644 --- a/tests/baselines/reference/correlatedUnions.types +++ b/tests/baselines/reference/correlatedUnions.types @@ -624,3 +624,74 @@ function f4(x: Funcs[keyof ArgMap], y: Funcs[K]) { >y : Funcs[K] } +// Repro from #47890 + +interface MyObj { + someKey: { +>someKey : { name: string; } + + name: string; +>name : string + } + someOtherKey: { +>someOtherKey : { name: number; } + + name: number; +>name : number + } +} + +const ref: MyObj = { +>ref : MyObj +>{ someKey: { name: "" }, someOtherKey: { name: 42 }} : { someKey: { name: string; }; someOtherKey: { name: number; }; } + + someKey: { name: "" }, +>someKey : { name: string; } +>{ name: "" } : { name: string; } +>name : string +>"" : "" + + someOtherKey: { name: 42 } +>someOtherKey : { name: number; } +>{ name: 42 } : { name: number; } +>name : number +>42 : 42 + +}; + +function func(k: K): MyObj[K]['name'] | undefined { +>func : (k: K) => MyObj[K]['name'] | undefined +>k : K + + const myObj: Partial[K] = ref[k]; +>myObj : Partial[K] +>ref[k] : MyObj[K] +>ref : MyObj +>k : K + + if (myObj) { +>myObj : Partial[K] + + return myObj.name; +>myObj.name : string | number +>myObj : { name: string; } | { name: number; } +>name : string | number + } + const myObj2: Partial[keyof MyObj] = ref[k]; +>myObj2 : { name: string; } | { name: number; } | undefined +>ref[k] : { name: string; } | { name: number; } +>ref : MyObj +>k : K + + if (myObj2) { +>myObj2 : { name: string; } | { name: number; } + + return myObj2.name; +>myObj2.name : string | number +>myObj2 : { name: string; } | { name: number; } +>name : string | number + } + return undefined; +>undefined : undefined +} + diff --git a/tests/cases/compiler/correlatedUnions.ts b/tests/cases/compiler/correlatedUnions.ts index 546d511034bae..f6b4086f03f5a 100644 --- a/tests/cases/compiler/correlatedUnions.ts +++ b/tests/cases/compiler/correlatedUnions.ts @@ -183,3 +183,31 @@ function f3(funcs: Funcs, key: K, arg: ArgMap[K]) { function f4(x: Funcs[keyof ArgMap], y: Funcs[K]) { x = y; } + +// Repro from #47890 + +interface MyObj { + someKey: { + name: string; + } + someOtherKey: { + name: number; + } +} + +const ref: MyObj = { + someKey: { name: "" }, + someOtherKey: { name: 42 } +}; + +function func(k: K): MyObj[K]['name'] | undefined { + const myObj: Partial[K] = ref[k]; + if (myObj) { + return myObj.name; + } + const myObj2: Partial[keyof MyObj] = ref[k]; + if (myObj2) { + return myObj2.name; + } + return undefined; +}