@@ -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({
@@ -11774,8 +11776,12 @@ namespace ts {
11774
11776
const simplified = getSimplifiedType((<IndexType>target).type);
11775
11777
const constraint = simplified !== (<IndexType>target).type ? simplified : getConstraintOfType((<IndexType>target).type);
11776
11778
if (constraint) {
11777
- if (result = isRelatedTo(source, getIndexType(constraint, (target as IndexType).stringsOnly), reportErrors)) {
11778
- return result;
11779
+ // We require Ternary.True here such that circular constraints don't cause
11780
+ // false positives. For example, given 'T extends { [K in keyof T]: string }',
11781
+ // 'keyof T' has itself as its constraint and produces a Ternary.Maybe when
11782
+ // related to other types.
11783
+ if (isRelatedTo(source, getIndexType(constraint, (target as IndexType).stringsOnly), reportErrors) === Ternary.True) {
11784
+ return Ternary.True;
11779
11785
}
11780
11786
}
11781
11787
}
@@ -14169,9 +14175,11 @@ namespace ts {
14169
14175
(type === falseType || type === regularFalseType) ? TypeFacts.FalseFacts : TypeFacts.TrueFacts;
14170
14176
}
14171
14177
if (flags & TypeFlags.Object) {
14172
- return isFunctionObjectType(<ObjectType>type) ?
14173
- strictNullChecks ? TypeFacts.FunctionStrictFacts : TypeFacts.FunctionFacts :
14174
- strictNullChecks ? TypeFacts.ObjectStrictFacts : TypeFacts.ObjectFacts;
14178
+ return getObjectFlags(type) & ObjectFlags.Anonymous && isEmptyObjectType(<ObjectType>type) ?
14179
+ strictNullChecks ? TypeFacts.EmptyObjectStrictFacts : TypeFacts.EmptyObjectFacts :
14180
+ isFunctionObjectType(<ObjectType>type) ?
14181
+ strictNullChecks ? TypeFacts.FunctionStrictFacts : TypeFacts.FunctionFacts :
14182
+ strictNullChecks ? TypeFacts.ObjectStrictFacts : TypeFacts.ObjectFacts;
14175
14183
}
14176
14184
if (flags & (TypeFlags.Void | TypeFlags.Undefined)) {
14177
14185
return TypeFacts.UndefinedFacts;
@@ -15083,23 +15091,24 @@ namespace ts {
15083
15091
return getTypeWithFacts(assumeTrue ? mapType(type, narrowTypeForTypeof) : type, facts);
15084
15092
15085
15093
function narrowTypeForTypeof(type: Type) {
15086
- if (assumeTrue && !(type.flags & TypeFlags.Union)) {
15087
- if (type.flags & TypeFlags.Unknown && literal.text === "object") {
15088
- return getUnionType([nonPrimitiveType, nullType]);
15089
- }
15090
- // We narrow a non-union type to an exact primitive type if the non-union type
15091
- // is a supertype of that primitive type. For example, type 'any' can be narrowed
15092
- // to one of the primitive types.
15093
- const targetType = literal.text === "function" ? globalFunctionType : typeofTypesByName.get(literal.text);
15094
- if (targetType) {
15095
- if (isTypeSubtypeOf(targetType, type)) {
15096
- return isTypeAny(type) ? targetType : getIntersectionType([type, targetType]); // Intersection to handle `string` being a subtype of `keyof T`
15097
- }
15098
- if (type.flags & TypeFlags.Instantiable) {
15099
- const constraint = getBaseConstraintOfType(type) || anyType;
15100
- if (isTypeSubtypeOf(targetType, constraint)) {
15101
- return getIntersectionType([type, targetType]);
15102
- }
15094
+ if (type.flags & TypeFlags.Unknown && literal.text === "object") {
15095
+ return getUnionType([nonPrimitiveType, nullType]);
15096
+ }
15097
+ // We narrow a non-union type to an exact primitive type if the non-union type
15098
+ // is a supertype of that primitive type. For example, type 'any' can be narrowed
15099
+ // to one of the primitive types.
15100
+ const targetType = literal.text === "function" ? globalFunctionType : typeofTypesByName.get(literal.text);
15101
+ if (targetType) {
15102
+ if (isTypeSubtypeOf(type, targetType)) {
15103
+ return type;
15104
+ }
15105
+ if (isTypeSubtypeOf(targetType, type)) {
15106
+ return targetType;
15107
+ }
15108
+ if (type.flags & TypeFlags.Instantiable) {
15109
+ const constraint = getBaseConstraintOfType(type) || anyType;
15110
+ if (isTypeSubtypeOf(targetType, constraint)) {
15111
+ return getIntersectionType([type, targetType]);
15103
15112
}
15104
15113
}
15105
15114
}
0 commit comments