@@ -245,7 +245,8 @@ namespace ts {
245245 NEUndefinedOrNull = 1 << 19, // x != undefined / x != null
246246 Truthy = 1 << 20, // x
247247 Falsy = 1 << 21, // !x
248- All = (1 << 22) - 1,
248+ Discriminatable = 1 << 22, // May have discriminant property
249+ All = (1 << 23) - 1,
249250 // The following members encode facts about particular kinds of types for use in the getTypeFacts function.
250251 // The presence of a particular fact means that the given test is true for some (and possibly all) values
251252 // of that kind of type.
@@ -275,9 +276,9 @@ namespace ts {
275276 TrueFacts = BaseBooleanFacts | Truthy,
276277 SymbolStrictFacts = TypeofEQSymbol | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | NEUndefined | NENull | NEUndefinedOrNull | Truthy,
277278 SymbolFacts = SymbolStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy,
278- ObjectStrictFacts = TypeofEQObject | TypeofEQHostObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | NEUndefined | NENull | NEUndefinedOrNull | Truthy,
279+ ObjectStrictFacts = TypeofEQObject | TypeofEQHostObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | NEUndefined | NENull | NEUndefinedOrNull | Truthy | Discriminatable ,
279280 ObjectFacts = ObjectStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy,
280- FunctionStrictFacts = TypeofEQFunction | TypeofEQHostObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | NEUndefined | NENull | NEUndefinedOrNull | Truthy,
281+ FunctionStrictFacts = TypeofEQFunction | TypeofEQHostObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | NEUndefined | NENull | NEUndefinedOrNull | Truthy | Discriminatable ,
281282 FunctionFacts = FunctionStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy,
282283 UndefinedFacts = TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | EQUndefined | EQUndefinedOrNull | NENull | Falsy,
283284 NullFacts = TypeofEQObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | TypeofNEHostObject | EQNull | EQUndefinedOrNull | NEUndefined | Falsy,
@@ -7848,17 +7849,24 @@ namespace ts {
78487849 }
78497850
78507851 function isDiscriminantProperty(type: Type, name: string) {
7851- if (type) {
7852- const nonNullType = getNonNullableType(type);
7853- if (nonNullType.flags & TypeFlags.Union) {
7854- const prop = getPropertyOfType(nonNullType, name);
7855- if (prop && prop.flags & SymbolFlags.SyntheticProperty) {
7856- if ((<TransientSymbol>prop).isDiscriminantProperty === undefined) {
7857- (<TransientSymbol>prop).isDiscriminantProperty = !(<TransientSymbol>prop).hasCommonType &&
7858- isUnitUnionType(getTypeOfSymbol(prop));
7859- }
7860- return (<TransientSymbol>prop).isDiscriminantProperty;
7861- }
7852+ if (type && type.flags & TypeFlags.Union) {
7853+ let prop = getPropertyOfType(type, name);
7854+ if (!prop) {
7855+ // The type may be a union that includes nullable or primtive types. If filtering
7856+ // those out produces a different type, get the property from that type instead.
7857+ // Effectively, we're checking if this *could* be a discriminant property once nullable
7858+ // and primitive types are removed by other type guards.
7859+ const filteredType = getTypeWithFacts(type, TypeFacts.Discriminatable);
7860+ if (filteredType !== type && filteredType.flags & TypeFlags.Union) {
7861+ prop = getPropertyOfType(type, name);
7862+ }
7863+ }
7864+ if (prop && prop.flags & SymbolFlags.SyntheticProperty) {
7865+ if ((<TransientSymbol>prop).isDiscriminantProperty === undefined) {
7866+ (<TransientSymbol>prop).isDiscriminantProperty = !(<TransientSymbol>prop).hasCommonType &&
7867+ isUnitUnionType(getTypeOfSymbol(prop));
7868+ }
7869+ return (<TransientSymbol>prop).isDiscriminantProperty;
78627870 }
78637871 }
78647872 return false;
0 commit comments