Skip to content

Commit e782cef

Browse files
authored
Properly handle partial union type properties in isTypePresencePossible (#53794)
1 parent 378ffa4 commit e782cef

10 files changed

+456
-1
lines changed

src/compiler/checker.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -27006,7 +27006,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2700627006
function isTypePresencePossible(type: Type, propName: __String, assumeTrue: boolean) {
2700727007
const prop = getPropertyOfType(type, propName);
2700827008
return prop ?
27009-
!!(prop.flags & SymbolFlags.Optional) || assumeTrue :
27009+
!!(prop.flags & SymbolFlags.Optional || getCheckFlags(prop) & CheckFlags.Partial) || assumeTrue :
2701027010
!!getApplicableIndexInfoForName(type, propName) || !assumeTrue;
2701127011
}
2701227012

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

+29
Original file line numberDiff line numberDiff line change
@@ -432,4 +432,33 @@ tests/cases/compiler/inKeywordTypeguard.ts(186,21): error TS2322: Type 'T' is no
432432
const f = <P extends object>(a: P & {}) => {
433433
"foo" in a;
434434
};
435+
436+
// Repro from #53773
437+
438+
function test1<T extends any[] | Record<string, any>>(obj: T) {
439+
if (Array.isArray(obj) || 'length' in obj) {
440+
obj; // T
441+
}
442+
else {
443+
obj; // T
444+
}
445+
}
446+
447+
function test2<T extends any[] | Record<string, any>>(obj: T) {
448+
if (Array.isArray(obj)) {
449+
obj; // T & any[]
450+
}
451+
else {
452+
obj; // T
453+
}
454+
}
455+
456+
function test3<T extends any[] | Record<string, any>>(obj: T) {
457+
if ('length' in obj) {
458+
obj; // T
459+
}
460+
else {
461+
obj; // T
462+
}
463+
}
435464

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

+54
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,35 @@ function isHTMLTable<T extends object | null>(table: T): boolean {
353353
const f = <P extends object>(a: P & {}) => {
354354
"foo" in a;
355355
};
356+
357+
// Repro from #53773
358+
359+
function test1<T extends any[] | Record<string, any>>(obj: T) {
360+
if (Array.isArray(obj) || 'length' in obj) {
361+
obj; // T
362+
}
363+
else {
364+
obj; // T
365+
}
366+
}
367+
368+
function test2<T extends any[] | Record<string, any>>(obj: T) {
369+
if (Array.isArray(obj)) {
370+
obj; // T & any[]
371+
}
372+
else {
373+
obj; // T
374+
}
375+
}
376+
377+
function test3<T extends any[] | Record<string, any>>(obj: T) {
378+
if ('length' in obj) {
379+
obj; // T
380+
}
381+
else {
382+
obj; // T
383+
}
384+
}
356385

357386

358387
//// [inKeywordTypeguard.js]
@@ -675,3 +704,28 @@ function isHTMLTable(table) {
675704
const f = (a) => {
676705
"foo" in a;
677706
};
707+
// Repro from #53773
708+
function test1(obj) {
709+
if (Array.isArray(obj) || 'length' in obj) {
710+
obj; // T
711+
}
712+
else {
713+
obj; // T
714+
}
715+
}
716+
function test2(obj) {
717+
if (Array.isArray(obj)) {
718+
obj; // T & any[]
719+
}
720+
else {
721+
obj; // T
722+
}
723+
}
724+
function test3(obj) {
725+
if ('length' in obj) {
726+
obj; // T
727+
}
728+
else {
729+
obj; // T
730+
}
731+
}

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

+66
Original file line numberDiff line numberDiff line change
@@ -879,3 +879,69 @@ const f = <P extends object>(a: P & {}) => {
879879

880880
};
881881

882+
// Repro from #53773
883+
884+
function test1<T extends any[] | Record<string, any>>(obj: T) {
885+
>test1 : Symbol(test1, Decl(inKeywordTypeguard.ts, 353, 2))
886+
>T : Symbol(T, Decl(inKeywordTypeguard.ts, 357, 15))
887+
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
888+
>obj : Symbol(obj, Decl(inKeywordTypeguard.ts, 357, 54))
889+
>T : Symbol(T, Decl(inKeywordTypeguard.ts, 357, 15))
890+
891+
if (Array.isArray(obj) || 'length' in obj) {
892+
>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
893+
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
894+
>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
895+
>obj : Symbol(obj, Decl(inKeywordTypeguard.ts, 357, 54))
896+
>obj : Symbol(obj, Decl(inKeywordTypeguard.ts, 357, 54))
897+
898+
obj; // T
899+
>obj : Symbol(obj, Decl(inKeywordTypeguard.ts, 357, 54))
900+
}
901+
else {
902+
obj; // T
903+
>obj : Symbol(obj, Decl(inKeywordTypeguard.ts, 357, 54))
904+
}
905+
}
906+
907+
function test2<T extends any[] | Record<string, any>>(obj: T) {
908+
>test2 : Symbol(test2, Decl(inKeywordTypeguard.ts, 364, 1))
909+
>T : Symbol(T, Decl(inKeywordTypeguard.ts, 366, 15))
910+
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
911+
>obj : Symbol(obj, Decl(inKeywordTypeguard.ts, 366, 54))
912+
>T : Symbol(T, Decl(inKeywordTypeguard.ts, 366, 15))
913+
914+
if (Array.isArray(obj)) {
915+
>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
916+
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
917+
>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
918+
>obj : Symbol(obj, Decl(inKeywordTypeguard.ts, 366, 54))
919+
920+
obj; // T & any[]
921+
>obj : Symbol(obj, Decl(inKeywordTypeguard.ts, 366, 54))
922+
}
923+
else {
924+
obj; // T
925+
>obj : Symbol(obj, Decl(inKeywordTypeguard.ts, 366, 54))
926+
}
927+
}
928+
929+
function test3<T extends any[] | Record<string, any>>(obj: T) {
930+
>test3 : Symbol(test3, Decl(inKeywordTypeguard.ts, 373, 1))
931+
>T : Symbol(T, Decl(inKeywordTypeguard.ts, 375, 15))
932+
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
933+
>obj : Symbol(obj, Decl(inKeywordTypeguard.ts, 375, 54))
934+
>T : Symbol(T, Decl(inKeywordTypeguard.ts, 375, 15))
935+
936+
if ('length' in obj) {
937+
>obj : Symbol(obj, Decl(inKeywordTypeguard.ts, 375, 54))
938+
939+
obj; // T
940+
>obj : Symbol(obj, Decl(inKeywordTypeguard.ts, 375, 54))
941+
}
942+
else {
943+
obj; // T
944+
>obj : Symbol(obj, Decl(inKeywordTypeguard.ts, 375, 54))
945+
}
946+
}
947+

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

+64
Original file line numberDiff line numberDiff line change
@@ -1085,3 +1085,67 @@ const f = <P extends object>(a: P & {}) => {
10851085

10861086
};
10871087

1088+
// Repro from #53773
1089+
1090+
function test1<T extends any[] | Record<string, any>>(obj: T) {
1091+
>test1 : <T extends any[] | Record<string, any>>(obj: T) => void
1092+
>obj : T
1093+
1094+
if (Array.isArray(obj) || 'length' in obj) {
1095+
>Array.isArray(obj) || 'length' in obj : boolean
1096+
>Array.isArray(obj) : boolean
1097+
>Array.isArray : (arg: any) => arg is any[]
1098+
>Array : ArrayConstructor
1099+
>isArray : (arg: any) => arg is any[]
1100+
>obj : any[] | Record<string, any>
1101+
>'length' in obj : boolean
1102+
>'length' : "length"
1103+
>obj : T
1104+
1105+
obj; // T
1106+
>obj : T
1107+
}
1108+
else {
1109+
obj; // T
1110+
>obj : T
1111+
}
1112+
}
1113+
1114+
function test2<T extends any[] | Record<string, any>>(obj: T) {
1115+
>test2 : <T extends any[] | Record<string, any>>(obj: T) => void
1116+
>obj : T
1117+
1118+
if (Array.isArray(obj)) {
1119+
>Array.isArray(obj) : boolean
1120+
>Array.isArray : (arg: any) => arg is any[]
1121+
>Array : ArrayConstructor
1122+
>isArray : (arg: any) => arg is any[]
1123+
>obj : any[] | Record<string, any>
1124+
1125+
obj; // T & any[]
1126+
>obj : T & any[]
1127+
}
1128+
else {
1129+
obj; // T
1130+
>obj : T
1131+
}
1132+
}
1133+
1134+
function test3<T extends any[] | Record<string, any>>(obj: T) {
1135+
>test3 : <T extends any[] | Record<string, any>>(obj: T) => void
1136+
>obj : T
1137+
1138+
if ('length' in obj) {
1139+
>'length' in obj : boolean
1140+
>'length' : "length"
1141+
>obj : T
1142+
1143+
obj; // T
1144+
>obj : T
1145+
}
1146+
else {
1147+
obj; // T
1148+
>obj : T
1149+
}
1150+
}
1151+

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

+29
Original file line numberDiff line numberDiff line change
@@ -452,4 +452,33 @@ tests/cases/compiler/inKeywordTypeguard.ts(186,21): error TS2638: Type 'NonNulla
452452
const f = <P extends object>(a: P & {}) => {
453453
"foo" in a;
454454
};
455+
456+
// Repro from #53773
457+
458+
function test1<T extends any[] | Record<string, any>>(obj: T) {
459+
if (Array.isArray(obj) || 'length' in obj) {
460+
obj; // T
461+
}
462+
else {
463+
obj; // T
464+
}
465+
}
466+
467+
function test2<T extends any[] | Record<string, any>>(obj: T) {
468+
if (Array.isArray(obj)) {
469+
obj; // T & any[]
470+
}
471+
else {
472+
obj; // T
473+
}
474+
}
475+
476+
function test3<T extends any[] | Record<string, any>>(obj: T) {
477+
if ('length' in obj) {
478+
obj; // T
479+
}
480+
else {
481+
obj; // T
482+
}
483+
}
455484

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

+54
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,35 @@ function isHTMLTable<T extends object | null>(table: T): boolean {
353353
const f = <P extends object>(a: P & {}) => {
354354
"foo" in a;
355355
};
356+
357+
// Repro from #53773
358+
359+
function test1<T extends any[] | Record<string, any>>(obj: T) {
360+
if (Array.isArray(obj) || 'length' in obj) {
361+
obj; // T
362+
}
363+
else {
364+
obj; // T
365+
}
366+
}
367+
368+
function test2<T extends any[] | Record<string, any>>(obj: T) {
369+
if (Array.isArray(obj)) {
370+
obj; // T & any[]
371+
}
372+
else {
373+
obj; // T
374+
}
375+
}
376+
377+
function test3<T extends any[] | Record<string, any>>(obj: T) {
378+
if ('length' in obj) {
379+
obj; // T
380+
}
381+
else {
382+
obj; // T
383+
}
384+
}
356385

357386

358387
//// [inKeywordTypeguard.js]
@@ -676,3 +705,28 @@ function isHTMLTable(table) {
676705
const f = (a) => {
677706
"foo" in a;
678707
};
708+
// Repro from #53773
709+
function test1(obj) {
710+
if (Array.isArray(obj) || 'length' in obj) {
711+
obj; // T
712+
}
713+
else {
714+
obj; // T
715+
}
716+
}
717+
function test2(obj) {
718+
if (Array.isArray(obj)) {
719+
obj; // T & any[]
720+
}
721+
else {
722+
obj; // T
723+
}
724+
}
725+
function test3(obj) {
726+
if ('length' in obj) {
727+
obj; // T
728+
}
729+
else {
730+
obj; // T
731+
}
732+
}

0 commit comments

Comments
 (0)