Merge pull request #26143 from mattmccutchen/issue-26130

Have getAssignmentReducedType use the comparable relation instead of typeMaybeAssignableTo.
This commit is contained in:
Anders Hejlsberg 2018-08-09 07:43:46 -07:00 committed by GitHub
commit 01f6093a9c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 120 additions and 15 deletions

View file

@ -13843,18 +13843,6 @@ namespace ts {
return flow.id;
}
function typeMaybeAssignableTo(source: Type, target: Type) {
if (!(source.flags & TypeFlags.Union)) {
return isTypeAssignableTo(source, target);
}
for (const t of (<UnionType>source).types) {
if (isTypeAssignableTo(t, target)) {
return true;
}
}
return false;
}
// Remove those constituent types of declaredType to which no constituent type of assignedType is assignable.
// For example, when a variable of type number | string | boolean is assigned a value of type number | boolean,
// we remove type string.
@ -13863,7 +13851,7 @@ namespace ts {
if (assignedType.flags & TypeFlags.Never) {
return assignedType;
}
const reducedType = filterType(declaredType, t => typeMaybeAssignableTo(assignedType, t));
const reducedType = filterType(declaredType, t => isTypeComparableTo(assignedType, t));
if (!(reducedType.flags & TypeFlags.Never)) {
return reducedType;
}

View file

@ -0,0 +1,23 @@
//// [assignmentGenericLookupTypeNarrowing.ts]
// Repro from #26130
let mappedObject: {[K in "foo"]: null | {x: string}} = {foo: {x: "hello"}};
declare function foo<T>(x: T): null | T;
function bar<K extends "foo">(key: K) {
const element = foo(mappedObject[key]);
if (element == null)
return;
const x = element.x;
}
//// [assignmentGenericLookupTypeNarrowing.js]
// Repro from #26130
var mappedObject = { foo: { x: "hello" } };
function bar(key) {
var element = foo(mappedObject[key]);
if (element == null)
return;
var x = element.x;
}

View file

@ -0,0 +1,40 @@
=== tests/cases/conformance/expressions/assignmentOperator/assignmentGenericLookupTypeNarrowing.ts ===
// Repro from #26130
let mappedObject: {[K in "foo"]: null | {x: string}} = {foo: {x: "hello"}};
>mappedObject : Symbol(mappedObject, Decl(assignmentGenericLookupTypeNarrowing.ts, 2, 3))
>K : Symbol(K, Decl(assignmentGenericLookupTypeNarrowing.ts, 2, 20))
>x : Symbol(x, Decl(assignmentGenericLookupTypeNarrowing.ts, 2, 41))
>foo : Symbol(foo, Decl(assignmentGenericLookupTypeNarrowing.ts, 2, 56))
>x : Symbol(x, Decl(assignmentGenericLookupTypeNarrowing.ts, 2, 62))
declare function foo<T>(x: T): null | T;
>foo : Symbol(foo, Decl(assignmentGenericLookupTypeNarrowing.ts, 2, 75))
>T : Symbol(T, Decl(assignmentGenericLookupTypeNarrowing.ts, 3, 21))
>x : Symbol(x, Decl(assignmentGenericLookupTypeNarrowing.ts, 3, 24))
>T : Symbol(T, Decl(assignmentGenericLookupTypeNarrowing.ts, 3, 21))
>T : Symbol(T, Decl(assignmentGenericLookupTypeNarrowing.ts, 3, 21))
function bar<K extends "foo">(key: K) {
>bar : Symbol(bar, Decl(assignmentGenericLookupTypeNarrowing.ts, 3, 40))
>K : Symbol(K, Decl(assignmentGenericLookupTypeNarrowing.ts, 5, 13))
>key : Symbol(key, Decl(assignmentGenericLookupTypeNarrowing.ts, 5, 30))
>K : Symbol(K, Decl(assignmentGenericLookupTypeNarrowing.ts, 5, 13))
const element = foo(mappedObject[key]);
>element : Symbol(element, Decl(assignmentGenericLookupTypeNarrowing.ts, 6, 7))
>foo : Symbol(foo, Decl(assignmentGenericLookupTypeNarrowing.ts, 2, 75))
>mappedObject : Symbol(mappedObject, Decl(assignmentGenericLookupTypeNarrowing.ts, 2, 3))
>key : Symbol(key, Decl(assignmentGenericLookupTypeNarrowing.ts, 5, 30))
if (element == null)
>element : Symbol(element, Decl(assignmentGenericLookupTypeNarrowing.ts, 6, 7))
return;
const x = element.x;
>x : Symbol(x, Decl(assignmentGenericLookupTypeNarrowing.ts, 9, 7))
>element.x : Symbol(x, Decl(assignmentGenericLookupTypeNarrowing.ts, 2, 41))
>element : Symbol(element, Decl(assignmentGenericLookupTypeNarrowing.ts, 6, 7))
>x : Symbol(x, Decl(assignmentGenericLookupTypeNarrowing.ts, 2, 41))
}

View file

@ -0,0 +1,43 @@
=== tests/cases/conformance/expressions/assignmentOperator/assignmentGenericLookupTypeNarrowing.ts ===
// Repro from #26130
let mappedObject: {[K in "foo"]: null | {x: string}} = {foo: {x: "hello"}};
>mappedObject : { foo: { x: string; }; }
>null : null
>x : string
>{foo: {x: "hello"}} : { foo: { x: string; }; }
>foo : { x: string; }
>{x: "hello"} : { x: string; }
>x : string
>"hello" : "hello"
declare function foo<T>(x: T): null | T;
>foo : <T>(x: T) => T
>x : T
>null : null
function bar<K extends "foo">(key: K) {
>bar : <K extends "foo">(key: K) => void
>key : K
const element = foo(mappedObject[key]);
>element : { foo: { x: string; }; }[K]
>foo(mappedObject[key]) : { foo: { x: string; }; }[K]
>foo : <T>(x: T) => T
>mappedObject[key] : { foo: { x: string; }; }[K]
>mappedObject : { foo: { x: string; }; }
>key : K
if (element == null)
>element == null : boolean
>element : { foo: { x: string; }; }[K]
>null : null
return;
const x = element.x;
>x : string
>element.x : string
>element : { foo: { x: string; }; }[K]
>x : string
}

View file

@ -252,9 +252,9 @@ abc = merged; // missing 'd'
>merged : Merged.E
merged = abc; // ok
>merged = abc : First.E
>merged = abc : First.E.a | First.E.b
>merged : Merged.E
>abc : First.E
>abc : First.E.a | First.E.b
abc = merged2; // ok
>abc = merged2 : Merged2.E

View file

@ -0,0 +1,11 @@
// Repro from #26130
let mappedObject: {[K in "foo"]: null | {x: string}} = {foo: {x: "hello"}};
declare function foo<T>(x: T): null | T;
function bar<K extends "foo">(key: K) {
const element = foo(mappedObject[key]);
if (element == null)
return;
const x = element.x;
}