Skip to content

Commit 5cd2d97

Browse files
authored
Fixed an issue with in not being able to be used on narrowed down expression of a generic nullable type (#51502)
* Fixed an issue with `in` not being able to be used on narrowed down expression of a generic nullable type * Add another test case from a new issue * Move the fix to `hasEmptyObjectIntersection`
1 parent 12d7e4b commit 5cd2d97

10 files changed

+191
-1
lines changed

src/compiler/checker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34998,7 +34998,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3499834998
}
3499934999

3500035000
function hasEmptyObjectIntersection(type: Type): boolean {
35001-
return someType(type, t => t === unknownEmptyObjectType || !!(t.flags & TypeFlags.Intersection) && some((t as IntersectionType).types, isEmptyAnonymousObjectType));
35001+
return someType(type, t => t === unknownEmptyObjectType || !!(t.flags & TypeFlags.Intersection) && isEmptyAnonymousObjectType(getBaseConstraintOrType(t)));
3500235002
}
3500335003

3500435004
function checkInExpression(left: Expression, right: Expression, leftType: Type, rightType: Type): Type {

tests/baselines/reference/inKeywordTypeguard(strict=false).errors.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,4 +420,16 @@ tests/cases/compiler/inKeywordTypeguard.ts(186,21): error TS2322: Type 'T' is no
420420

421421
const checkIsTouchDevice = () =>
422422
"ontouchstart" in window || "msMaxTouchPoints" in window.navigator;
423+
424+
// Repro from #51501
425+
426+
function isHTMLTable<T extends object | null>(table: T): boolean {
427+
return !!table && 'html' in table;
428+
}
429+
430+
// Repro from #51549
431+
432+
const f = <P extends object>(a: P & {}) => {
433+
"foo" in a;
434+
};
423435

tests/baselines/reference/inKeywordTypeguard(strict=false).js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,18 @@ function foo<A>(value: A) {
341341

342342
const checkIsTouchDevice = () =>
343343
"ontouchstart" in window || "msMaxTouchPoints" in window.navigator;
344+
345+
// Repro from #51501
346+
347+
function isHTMLTable<T extends object | null>(table: T): boolean {
348+
return !!table && 'html' in table;
349+
}
350+
351+
// Repro from #51549
352+
353+
const f = <P extends object>(a: P & {}) => {
354+
"foo" in a;
355+
};
344356

345357

346358
//// [inKeywordTypeguard.js]
@@ -655,3 +667,11 @@ function foo(value) {
655667
}
656668
// Repro from #50954
657669
const checkIsTouchDevice = () => "ontouchstart" in window || "msMaxTouchPoints" in window.navigator;
670+
// Repro from #51501
671+
function isHTMLTable(table) {
672+
return !!table && 'html' in table;
673+
}
674+
// Repro from #51549
675+
const f = (a) => {
676+
"foo" in a;
677+
};

tests/baselines/reference/inKeywordTypeguard(strict=false).symbols

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -853,3 +853,29 @@ const checkIsTouchDevice = () =>
853853
>window : Symbol(window, Decl(lib.dom.d.ts, --, --))
854854
>navigator : Symbol(navigator, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --))
855855

856+
// Repro from #51501
857+
858+
function isHTMLTable<T extends object | null>(table: T): boolean {
859+
>isHTMLTable : Symbol(isHTMLTable, Decl(inKeywordTypeguard.ts, 341, 71))
860+
>T : Symbol(T, Decl(inKeywordTypeguard.ts, 345, 21))
861+
>table : Symbol(table, Decl(inKeywordTypeguard.ts, 345, 46))
862+
>T : Symbol(T, Decl(inKeywordTypeguard.ts, 345, 21))
863+
864+
return !!table && 'html' in table;
865+
>table : Symbol(table, Decl(inKeywordTypeguard.ts, 345, 46))
866+
>table : Symbol(table, Decl(inKeywordTypeguard.ts, 345, 46))
867+
}
868+
869+
// Repro from #51549
870+
871+
const f = <P extends object>(a: P & {}) => {
872+
>f : Symbol(f, Decl(inKeywordTypeguard.ts, 351, 5))
873+
>P : Symbol(P, Decl(inKeywordTypeguard.ts, 351, 11))
874+
>a : Symbol(a, Decl(inKeywordTypeguard.ts, 351, 29))
875+
>P : Symbol(P, Decl(inKeywordTypeguard.ts, 351, 11))
876+
877+
"foo" in a;
878+
>a : Symbol(a, Decl(inKeywordTypeguard.ts, 351, 29))
879+
880+
};
881+

tests/baselines/reference/inKeywordTypeguard(strict=false).types

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,3 +1056,34 @@ const checkIsTouchDevice = () =>
10561056
>window : Window & typeof globalThis
10571057
>navigator : Navigator
10581058

1059+
// Repro from #51501
1060+
1061+
function isHTMLTable<T extends object | null>(table: T): boolean {
1062+
>isHTMLTable : <T extends object>(table: T) => boolean
1063+
>null : null
1064+
>table : T
1065+
1066+
return !!table && 'html' in table;
1067+
>!!table && 'html' in table : boolean
1068+
>!!table : boolean
1069+
>!table : boolean
1070+
>table : T
1071+
>'html' in table : boolean
1072+
>'html' : "html"
1073+
>table : T
1074+
}
1075+
1076+
// Repro from #51549
1077+
1078+
const f = <P extends object>(a: P & {}) => {
1079+
>f : <P extends object>(a: P & {}) => void
1080+
><P extends object>(a: P & {}) => { "foo" in a;} : <P extends object>(a: P & {}) => void
1081+
>a : P & {}
1082+
1083+
"foo" in a;
1084+
>"foo" in a : boolean
1085+
>"foo" : "foo"
1086+
>a : P & {}
1087+
1088+
};
1089+

tests/baselines/reference/inKeywordTypeguard(strict=true).errors.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,4 +440,16 @@ tests/cases/compiler/inKeywordTypeguard.ts(186,21): error TS2638: Type 'NonNulla
440440

441441
const checkIsTouchDevice = () =>
442442
"ontouchstart" in window || "msMaxTouchPoints" in window.navigator;
443+
444+
// Repro from #51501
445+
446+
function isHTMLTable<T extends object | null>(table: T): boolean {
447+
return !!table && 'html' in table;
448+
}
449+
450+
// Repro from #51549
451+
452+
const f = <P extends object>(a: P & {}) => {
453+
"foo" in a;
454+
};
443455

tests/baselines/reference/inKeywordTypeguard(strict=true).js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,18 @@ function foo<A>(value: A) {
341341

342342
const checkIsTouchDevice = () =>
343343
"ontouchstart" in window || "msMaxTouchPoints" in window.navigator;
344+
345+
// Repro from #51501
346+
347+
function isHTMLTable<T extends object | null>(table: T): boolean {
348+
return !!table && 'html' in table;
349+
}
350+
351+
// Repro from #51549
352+
353+
const f = <P extends object>(a: P & {}) => {
354+
"foo" in a;
355+
};
344356

345357

346358
//// [inKeywordTypeguard.js]
@@ -656,3 +668,11 @@ function foo(value) {
656668
}
657669
// Repro from #50954
658670
const checkIsTouchDevice = () => "ontouchstart" in window || "msMaxTouchPoints" in window.navigator;
671+
// Repro from #51501
672+
function isHTMLTable(table) {
673+
return !!table && 'html' in table;
674+
}
675+
// Repro from #51549
676+
const f = (a) => {
677+
"foo" in a;
678+
};

tests/baselines/reference/inKeywordTypeguard(strict=true).symbols

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -853,3 +853,29 @@ const checkIsTouchDevice = () =>
853853
>window : Symbol(window, Decl(lib.dom.d.ts, --, --))
854854
>navigator : Symbol(navigator, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --))
855855

856+
// Repro from #51501
857+
858+
function isHTMLTable<T extends object | null>(table: T): boolean {
859+
>isHTMLTable : Symbol(isHTMLTable, Decl(inKeywordTypeguard.ts, 341, 71))
860+
>T : Symbol(T, Decl(inKeywordTypeguard.ts, 345, 21))
861+
>table : Symbol(table, Decl(inKeywordTypeguard.ts, 345, 46))
862+
>T : Symbol(T, Decl(inKeywordTypeguard.ts, 345, 21))
863+
864+
return !!table && 'html' in table;
865+
>table : Symbol(table, Decl(inKeywordTypeguard.ts, 345, 46))
866+
>table : Symbol(table, Decl(inKeywordTypeguard.ts, 345, 46))
867+
}
868+
869+
// Repro from #51549
870+
871+
const f = <P extends object>(a: P & {}) => {
872+
>f : Symbol(f, Decl(inKeywordTypeguard.ts, 351, 5))
873+
>P : Symbol(P, Decl(inKeywordTypeguard.ts, 351, 11))
874+
>a : Symbol(a, Decl(inKeywordTypeguard.ts, 351, 29))
875+
>P : Symbol(P, Decl(inKeywordTypeguard.ts, 351, 11))
876+
877+
"foo" in a;
878+
>a : Symbol(a, Decl(inKeywordTypeguard.ts, 351, 29))
879+
880+
};
881+

tests/baselines/reference/inKeywordTypeguard(strict=true).types

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,3 +1056,34 @@ const checkIsTouchDevice = () =>
10561056
>window : Window & typeof globalThis
10571057
>navigator : Navigator
10581058

1059+
// Repro from #51501
1060+
1061+
function isHTMLTable<T extends object | null>(table: T): boolean {
1062+
>isHTMLTable : <T extends object | null>(table: T) => boolean
1063+
>null : null
1064+
>table : T
1065+
1066+
return !!table && 'html' in table;
1067+
>!!table && 'html' in table : boolean
1068+
>!!table : boolean
1069+
>!table : boolean
1070+
>table : T
1071+
>'html' in table : boolean
1072+
>'html' : "html"
1073+
>table : NonNullable<T>
1074+
}
1075+
1076+
// Repro from #51549
1077+
1078+
const f = <P extends object>(a: P & {}) => {
1079+
>f : <P extends object>(a: P & {}) => void
1080+
><P extends object>(a: P & {}) => { "foo" in a;} : <P extends object>(a: P & {}) => void
1081+
>a : P & {}
1082+
1083+
"foo" in a;
1084+
>"foo" in a : boolean
1085+
>"foo" : "foo"
1086+
>a : P & {}
1087+
1088+
};
1089+

tests/cases/compiler/inKeywordTypeguard.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,3 +343,15 @@ function foo<A>(value: A) {
343343

344344
const checkIsTouchDevice = () =>
345345
"ontouchstart" in window || "msMaxTouchPoints" in window.navigator;
346+
347+
// Repro from #51501
348+
349+
function isHTMLTable<T extends object | null>(table: T): boolean {
350+
return !!table && 'html' in table;
351+
}
352+
353+
// Repro from #51549
354+
355+
const f = <P extends object>(a: P & {}) => {
356+
"foo" in a;
357+
};

0 commit comments

Comments
 (0)