diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 85c01429e4ce6..51df774650e8d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -25150,7 +25150,7 @@ namespace ts { function narrowByInKeyword(type: Type, name: __String, assumeTrue: boolean) { if (type.flags & TypeFlags.Union - || type.flags & TypeFlags.Object && declaredType !== type + || type.flags & TypeFlags.Object && declaredType !== type && !(declaredType === unknownType && isEmptyAnonymousObjectType(type)) || isThisTypeParameter(type) || type.flags & TypeFlags.Intersection && every((type as IntersectionType).types, t => t.symbol !== globalThisSymbol)) { return filterType(type, t => isTypePresencePossible(t, name, assumeTrue)); diff --git a/tests/baselines/reference/inKeywordAndUnknown.js b/tests/baselines/reference/inKeywordAndUnknown.js new file mode 100644 index 0000000000000..354bb8c4b1884 --- /dev/null +++ b/tests/baselines/reference/inKeywordAndUnknown.js @@ -0,0 +1,36 @@ +//// [inKeywordAndUnknown.ts] +// Repro from #50531 + +function f(x: {}, y: unknown) { + if (!("a" in x)) { + return; + } + x; // {} + if (!y) { + return; + } + y; // {} + if (!("a" in y)) { + return; + } + y; // {} +} + + +//// [inKeywordAndUnknown.js] +"use strict"; +// Repro from #50531 +function f(x, y) { + if (!("a" in x)) { + return; + } + x; // {} + if (!y) { + return; + } + y; // {} + if (!("a" in y)) { + return; + } + y; // {} +} diff --git a/tests/baselines/reference/inKeywordAndUnknown.symbols b/tests/baselines/reference/inKeywordAndUnknown.symbols new file mode 100644 index 0000000000000..145e92dc7f657 --- /dev/null +++ b/tests/baselines/reference/inKeywordAndUnknown.symbols @@ -0,0 +1,33 @@ +=== tests/cases/compiler/inKeywordAndUnknown.ts === +// Repro from #50531 + +function f(x: {}, y: unknown) { +>f : Symbol(f, Decl(inKeywordAndUnknown.ts, 0, 0)) +>x : Symbol(x, Decl(inKeywordAndUnknown.ts, 2, 11)) +>y : Symbol(y, Decl(inKeywordAndUnknown.ts, 2, 17)) + + if (!("a" in x)) { +>x : Symbol(x, Decl(inKeywordAndUnknown.ts, 2, 11)) + + return; + } + x; // {} +>x : Symbol(x, Decl(inKeywordAndUnknown.ts, 2, 11)) + + if (!y) { +>y : Symbol(y, Decl(inKeywordAndUnknown.ts, 2, 17)) + + return; + } + y; // {} +>y : Symbol(y, Decl(inKeywordAndUnknown.ts, 2, 17)) + + if (!("a" in y)) { +>y : Symbol(y, Decl(inKeywordAndUnknown.ts, 2, 17)) + + return; + } + y; // {} +>y : Symbol(y, Decl(inKeywordAndUnknown.ts, 2, 17)) +} + diff --git a/tests/baselines/reference/inKeywordAndUnknown.types b/tests/baselines/reference/inKeywordAndUnknown.types new file mode 100644 index 0000000000000..74345ca004547 --- /dev/null +++ b/tests/baselines/reference/inKeywordAndUnknown.types @@ -0,0 +1,42 @@ +=== tests/cases/compiler/inKeywordAndUnknown.ts === +// Repro from #50531 + +function f(x: {}, y: unknown) { +>f : (x: {}, y: unknown) => void +>x : {} +>y : unknown + + if (!("a" in x)) { +>!("a" in x) : boolean +>("a" in x) : boolean +>"a" in x : boolean +>"a" : "a" +>x : {} + + return; + } + x; // {} +>x : {} + + if (!y) { +>!y : boolean +>y : unknown + + return; + } + y; // {} +>y : {} + + if (!("a" in y)) { +>!("a" in y) : boolean +>("a" in y) : boolean +>"a" in y : boolean +>"a" : "a" +>y : {} + + return; + } + y; // {} +>y : {} +} + diff --git a/tests/cases/compiler/inKeywordAndUnknown.ts b/tests/cases/compiler/inKeywordAndUnknown.ts new file mode 100644 index 0000000000000..745dfbc1f9af5 --- /dev/null +++ b/tests/cases/compiler/inKeywordAndUnknown.ts @@ -0,0 +1,18 @@ +// @strict: true + +// Repro from #50531 + +function f(x: {}, y: unknown) { + if (!("a" in x)) { + return; + } + x; // {} + if (!y) { + return; + } + y; // {} + if (!("a" in y)) { + return; + } + y; // {} +}