diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3c307585a9..19012235d5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13791,18 +13791,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 (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. @@ -13811,7 +13799,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; } diff --git a/tests/baselines/reference/assignmentGenericLookupTypeNarrowing.js b/tests/baselines/reference/assignmentGenericLookupTypeNarrowing.js new file mode 100644 index 0000000000..7f757ef24c --- /dev/null +++ b/tests/baselines/reference/assignmentGenericLookupTypeNarrowing.js @@ -0,0 +1,23 @@ +//// [assignmentGenericLookupTypeNarrowing.ts] +// Repro from #26130 + +let mappedObject: {[K in "foo"]: null | {x: string}} = {foo: {x: "hello"}}; +declare function foo(x: T): null | T; + +function bar(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; +} diff --git a/tests/baselines/reference/assignmentGenericLookupTypeNarrowing.symbols b/tests/baselines/reference/assignmentGenericLookupTypeNarrowing.symbols new file mode 100644 index 0000000000..f256ef8c1b --- /dev/null +++ b/tests/baselines/reference/assignmentGenericLookupTypeNarrowing.symbols @@ -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(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(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)) +} + diff --git a/tests/baselines/reference/assignmentGenericLookupTypeNarrowing.types b/tests/baselines/reference/assignmentGenericLookupTypeNarrowing.types new file mode 100644 index 0000000000..5de987b283 --- /dev/null +++ b/tests/baselines/reference/assignmentGenericLookupTypeNarrowing.types @@ -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(x: T): null | T; +>foo : (x: T) => T +>x : T +>null : null + +function bar(key: K) { +>bar : (key: K) => void +>key : K + + const element = foo(mappedObject[key]); +>element : { foo: { x: string; }; }[K] +>foo(mappedObject[key]) : { foo: { x: string; }; }[K] +>foo : (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 +} + diff --git a/tests/baselines/reference/enumAssignmentCompat3.types b/tests/baselines/reference/enumAssignmentCompat3.types index a152cd624d..f2a693515e 100644 --- a/tests/baselines/reference/enumAssignmentCompat3.types +++ b/tests/baselines/reference/enumAssignmentCompat3.types @@ -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 diff --git a/tests/cases/conformance/expressions/assignmentOperator/assignmentGenericLookupTypeNarrowing.ts b/tests/cases/conformance/expressions/assignmentOperator/assignmentGenericLookupTypeNarrowing.ts new file mode 100644 index 0000000000..c60ad06c1f --- /dev/null +++ b/tests/cases/conformance/expressions/assignmentOperator/assignmentGenericLookupTypeNarrowing.ts @@ -0,0 +1,11 @@ +// Repro from #26130 + +let mappedObject: {[K in "foo"]: null | {x: string}} = {foo: {x: "hello"}}; +declare function foo(x: T): null | T; + +function bar(key: K) { + const element = foo(mappedObject[key]); + if (element == null) + return; + const x = element.x; +}