Skip to content

Commit

Permalink
Cherry-pick PR #47953 into release-4.6 (#47957)
Browse files Browse the repository at this point in the history
Component commits:
aa1c25d Remove unnecessary check in getNarrowableTypeForReference

f4dcf88 Add regression test

Co-authored-by: Anders Hejlsberg <andersh@microsoft.com>
  • Loading branch information
TypeScript Bot and ahejlsberg authored Feb 19, 2022
1 parent 57bd608 commit ded20c6
Show file tree
Hide file tree
Showing 5 changed files with 231 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
53 changes: 53 additions & 0 deletions tests/baselines/reference/correlatedUnions.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,34 @@ function f3<K extends keyof ArgMap>(funcs: Funcs, key: K, arg: ArgMap[K]) {
function f4<K extends keyof ArgMap>(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 extends keyof MyObj>(k: K): MyObj[K]['name'] | undefined {
const myObj: Partial<MyObj>[K] = ref[k];
if (myObj) {
return myObj.name;
}
const myObj2: Partial<MyObj>[keyof MyObj] = ref[k];
if (myObj2) {
return myObj2.name;
}
return undefined;
}


//// [correlatedUnions.js]
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -398,3 +441,13 @@ declare function f1<K extends keyof ArgMap>(funcs: Funcs, key: K, arg: ArgMap[K]
declare function f2<K extends keyof ArgMap>(funcs: Funcs, key: K, arg: ArgMap[K]): void;
declare function f3<K extends keyof ArgMap>(funcs: Funcs, key: K, arg: ArgMap[K]): void;
declare function f4<K extends keyof ArgMap>(x: Funcs[keyof ArgMap], y: Funcs[K]): void;
interface MyObj {
someKey: {
name: string;
};
someOtherKey: {
name: number;
};
}
declare const ref: MyObj;
declare function func<K extends keyof MyObj>(k: K): MyObj[K]['name'] | undefined;
78 changes: 78 additions & 0 deletions tests/baselines/reference/correlatedUnions.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -675,3 +675,81 @@ function f4<K extends keyof ArgMap>(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 extends keyof MyObj>(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<MyObj>[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<MyObj>[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)
}

71 changes: 71 additions & 0 deletions tests/baselines/reference/correlatedUnions.types
Original file line number Diff line number Diff line change
Expand Up @@ -624,3 +624,74 @@ function f4<K extends keyof ArgMap>(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 extends keyof MyObj>(k: K): MyObj[K]['name'] | undefined {
>func : <K extends keyof MyObj>(k: K) => MyObj[K]['name'] | undefined
>k : K

const myObj: Partial<MyObj>[K] = ref[k];
>myObj : Partial<MyObj>[K]
>ref[k] : MyObj[K]
>ref : MyObj
>k : K

if (myObj) {
>myObj : Partial<MyObj>[K]

return myObj.name;
>myObj.name : string | number
>myObj : { name: string; } | { name: number; }
>name : string | number
}
const myObj2: Partial<MyObj>[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
}

28 changes: 28 additions & 0 deletions tests/cases/compiler/correlatedUnions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,31 @@ function f3<K extends keyof ArgMap>(funcs: Funcs, key: K, arg: ArgMap[K]) {
function f4<K extends keyof ArgMap>(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 extends keyof MyObj>(k: K): MyObj[K]['name'] | undefined {
const myObj: Partial<MyObj>[K] = ref[k];
if (myObj) {
return myObj.name;
}
const myObj2: Partial<MyObj>[keyof MyObj] = ref[k];
if (myObj2) {
return myObj2.name;
}
return undefined;
}

0 comments on commit ded20c6

Please sign in to comment.