@@ -8959,15 +8959,32 @@ namespace ts {
8959
8959
// unless all of target.types are weak, in which case run weak type detection on the *combined* properties of target
8960
8960
// at a minimum, do the first part.
8961
8961
// but the thing should be flexible enough to easily do the second part as a separate call
8962
+ const saveDynamicDisableWeakTypeErrors = dynamicDisableWeakTypeErrors;
8963
+ dynamicDisableWeakTypeErrors = true;
8962
8964
for (const targetType of targetTypes) {
8963
- dynamicDisableWeakTypeErrors = true;
8964
8965
const related = isRelatedTo(source, targetType, reportErrors);
8965
- dynamicDisableWeakTypeErrors = false;
8966
8966
if (!related) {
8967
+ dynamicDisableWeakTypeErrors = saveDynamicDisableWeakTypeErrors;
8967
8968
return Ternary.False;
8968
8969
}
8969
8970
result &= related;
8970
8971
}
8972
+ dynamicDisableWeakTypeErrors = saveDynamicDisableWeakTypeErrors;
8973
+ if (source !== globalObjectType && getPropertiesOfType(source).length > 0 && every(target.types, isWeak)) {
8974
+ let found = false;
8975
+ for (const property of getPropertiesOfType(source)) {
8976
+ if (isKnownProperty(target, property.name, /*isComparingJsxAttributes*/ false)) {
8977
+ found = true;
8978
+ break;
8979
+ }
8980
+ }
8981
+ if (!found) {
8982
+ if (reportErrors) {
8983
+ reportError(Diagnostics.Weak_type_0_has_no_properties_in_common_with_1, typeToString(target), typeToString(source));
8984
+ }
8985
+ return Ternary.False;
8986
+ }
8987
+ }
8971
8988
return result;
8972
8989
}
8973
8990
@@ -9340,7 +9357,7 @@ namespace ts {
9340
9357
}
9341
9358
}
9342
9359
}
9343
- if (!foundMatchingProperty && !dynamicDisableWeakTypeErrors && getPropertiesOfType(source).length > 0) {
9360
+ if (!foundMatchingProperty && !dynamicDisableWeakTypeErrors && source !== globalObjectType && getPropertiesOfType(source).length > 0) {
9344
9361
if (reportErrors) {
9345
9362
reportError(Diagnostics.Weak_type_0_has_no_properties_in_common_with_1, typeToString(target), typeToString(source));
9346
9363
}
@@ -9349,6 +9366,17 @@ namespace ts {
9349
9366
return result;
9350
9367
}
9351
9368
9369
+ // A type is 'weak' if it is an object type with at least one optional property
9370
+ // and no required properties or index signatures
9371
+ function isWeak(type: Type) {
9372
+ let props = getPropertiesOfType(type);
9373
+ return type.flags & TypeFlags.Object &&
9374
+ props.length > 0 &&
9375
+ every(props, p => !!(p.flags & SymbolFlags.Optional)) &&
9376
+ !getIndexTypeOfType(type, IndexKind.String) &&
9377
+ !getIndexTypeOfType(type, IndexKind.Number);
9378
+ }
9379
+
9352
9380
function propertiesIdenticalTo(source: Type, target: Type): Ternary {
9353
9381
if (!(source.flags & TypeFlags.Object && target.flags & TypeFlags.Object)) {
9354
9382
return Ternary.False;
@@ -10604,25 +10632,13 @@ namespace ts {
10604
10632
return links.resolvedSymbol;
10605
10633
}
10606
10634
10607
- // A type is 'weak' if it is an object type with at least one optional property
10608
- // and no required properties or index signatures
10609
- function isWeak(type: Type) {
10610
- let props = getPropertiesOfType(type);
10611
- return type.flags & TypeFlags.Object &&
10612
- props.length > 0 &&
10613
- every(props, p => !!(p.flags & SymbolFlags.Optional)) &&
10614
- !getIndexTypeOfType(type, IndexKind.String) &&
10615
- !getIndexTypeOfType(type, IndexKind.Number);
10616
- }
10617
-
10618
10635
function isInTypeQuery(node: Node): boolean {
10619
10636
// TypeScript 1.0 spec (April 2014): 3.6.3
10620
10637
// A type query consists of the keyword typeof followed by an expression.
10621
10638
// The expression is restricted to a single identifier or a sequence of identifiers separated by periods
10622
10639
return !!findAncestor(
10623
10640
node,
10624
10641
n => n.kind === SyntaxKind.TypeQuery ? true : n.kind === SyntaxKind.Identifier || n.kind === SyntaxKind.QualifiedName ? false : "quit");
10625
-
10626
10642
}
10627
10643
10628
10644
// Return the flow cache key for a "dotted name" (i.e. a sequence of identifiers
@@ -14124,8 +14140,10 @@ namespace ts {
14124
14140
function isKnownProperty(targetType: Type, name: string, isComparingJsxAttributes: boolean): boolean {
14125
14141
if (targetType.flags & TypeFlags.Object) {
14126
14142
const resolved = resolveStructuredTypeMembers(<ObjectType>targetType);
14127
- if (resolved.stringIndexInfo || resolved.numberIndexInfo && isNumericLiteralName(name) ||
14128
- getPropertyOfType(targetType, name) || isComparingJsxAttributes && !isUnhyphenatedJsxName(name)) {
14143
+ if (resolved.stringIndexInfo ||
14144
+ resolved.numberIndexInfo && isNumericLiteralName(name) ||
14145
+ getPropertyOfType(targetType, name) ||
14146
+ isComparingJsxAttributes && !isUnhyphenatedJsxName(name)) {
14129
14147
// For JSXAttributes, if the attribute has a hyphenated name, consider that the attribute to be known.
14130
14148
return true;
14131
14149
}
0 commit comments