@@ -601,6 +601,8 @@ namespace ts {
601
601
FunctionFacts = FunctionStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy,
602
602
UndefinedFacts = TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | EQUndefined | EQUndefinedOrNull | NENull | Falsy,
603
603
NullFacts = TypeofEQObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | TypeofNEHostObject | EQNull | EQUndefinedOrNull | NEUndefined | Falsy,
604
+ EmptyObjectStrictFacts = All & ~(EQUndefined | EQNull | EQUndefinedOrNull),
605
+ EmptyObjectFacts = All,
604
606
}
605
607
606
608
const typeofEQFacts = createMapFromTemplate({
@@ -11836,8 +11838,12 @@ namespace ts {
11836
11838
const simplified = getSimplifiedType((<IndexType>target).type);
11837
11839
const constraint = simplified !== (<IndexType>target).type ? simplified : getConstraintOfType((<IndexType>target).type);
11838
11840
if (constraint) {
11839
- if (result = isRelatedTo(source, getIndexType(constraint, (target as IndexType).stringsOnly), reportErrors)) {
11840
- return result;
11841
+ // We require Ternary.True here such that circular constraints don't cause
11842
+ // false positives. For example, given 'T extends { [K in keyof T]: string }',
11843
+ // 'keyof T' has itself as its constraint and produces a Ternary.Maybe when
11844
+ // related to other types.
11845
+ if (isRelatedTo(source, getIndexType(constraint, (target as IndexType).stringsOnly), reportErrors) === Ternary.True) {
11846
+ return Ternary.True;
11841
11847
}
11842
11848
}
11843
11849
}
@@ -14241,9 +14247,11 @@ namespace ts {
14241
14247
(type === falseType || type === regularFalseType) ? TypeFacts.FalseFacts : TypeFacts.TrueFacts;
14242
14248
}
14243
14249
if (flags & TypeFlags.Object) {
14244
- return isFunctionObjectType(<ObjectType>type) ?
14245
- strictNullChecks ? TypeFacts.FunctionStrictFacts : TypeFacts.FunctionFacts :
14246
- strictNullChecks ? TypeFacts.ObjectStrictFacts : TypeFacts.ObjectFacts;
14250
+ return getObjectFlags(type) & ObjectFlags.Anonymous && isEmptyObjectType(<ObjectType>type) ?
14251
+ strictNullChecks ? TypeFacts.EmptyObjectStrictFacts : TypeFacts.EmptyObjectFacts :
14252
+ isFunctionObjectType(<ObjectType>type) ?
14253
+ strictNullChecks ? TypeFacts.FunctionStrictFacts : TypeFacts.FunctionFacts :
14254
+ strictNullChecks ? TypeFacts.ObjectStrictFacts : TypeFacts.ObjectFacts;
14247
14255
}
14248
14256
if (flags & (TypeFlags.Void | TypeFlags.Undefined)) {
14249
14257
return TypeFacts.UndefinedFacts;
@@ -15163,23 +15171,24 @@ namespace ts {
15163
15171
return getTypeWithFacts(assumeTrue ? mapType(type, narrowTypeForTypeof) : type, facts);
15164
15172
15165
15173
function narrowTypeForTypeof(type: Type) {
15166
- if (assumeTrue && !(type.flags & TypeFlags.Union)) {
15167
- if (type.flags & TypeFlags.Unknown && literal.text === "object") {
15168
- return getUnionType([nonPrimitiveType, nullType]);
15169
- }
15170
- // We narrow a non-union type to an exact primitive type if the non-union type
15171
- // is a supertype of that primitive type. For example, type 'any' can be narrowed
15172
- // to one of the primitive types.
15173
- const targetType = literal.text === "function" ? globalFunctionType : typeofTypesByName.get(literal.text);
15174
- if (targetType) {
15175
- if (isTypeSubtypeOf(targetType, type)) {
15176
- return isTypeAny(type) ? targetType : getIntersectionType([type, targetType]); // Intersection to handle `string` being a subtype of `keyof T`
15177
- }
15178
- if (type.flags & TypeFlags.Instantiable) {
15179
- const constraint = getBaseConstraintOfType(type) || anyType;
15180
- if (isTypeSubtypeOf(targetType, constraint)) {
15181
- return getIntersectionType([type, targetType]);
15182
- }
15174
+ if (type.flags & TypeFlags.Unknown && literal.text === "object") {
15175
+ return getUnionType([nonPrimitiveType, nullType]);
15176
+ }
15177
+ // We narrow a non-union type to an exact primitive type if the non-union type
15178
+ // is a supertype of that primitive type. For example, type 'any' can be narrowed
15179
+ // to one of the primitive types.
15180
+ const targetType = literal.text === "function" ? globalFunctionType : typeofTypesByName.get(literal.text);
15181
+ if (targetType) {
15182
+ if (isTypeSubtypeOf(type, targetType)) {
15183
+ return type;
15184
+ }
15185
+ if (isTypeSubtypeOf(targetType, type)) {
15186
+ return targetType;
15187
+ }
15188
+ if (type.flags & TypeFlags.Instantiable) {
15189
+ const constraint = getBaseConstraintOfType(type) || anyType;
15190
+ if (isTypeSubtypeOf(targetType, constraint)) {
15191
+ return getIntersectionType([type, targetType]);
15183
15192
}
15184
15193
}
15185
15194
}
0 commit comments