@@ -8701,7 +8701,7 @@ namespace ts {
8701
8701
let expandingFlags: number;
8702
8702
let depth = 0;
8703
8703
let overflow = false;
8704
- let disableWeakTypeCheckingForIntersectionConstituents = false;
8704
+ let isIntersectionConstituent = false;
8705
8705
8706
8706
Debug.assert(relation !== identityRelation || !errorNode, "no error reporting in identity checking");
8707
8707
@@ -8784,7 +8784,6 @@ namespace ts {
8784
8784
* * Ternary.False if they are not related.
8785
8785
*/
8786
8786
function isRelatedTo(source: Type, target: Type, reportErrors?: boolean, headMessage?: DiagnosticMessage): Ternary {
8787
- let result: Ternary;
8788
8787
if (source.flags & TypeFlags.StringOrNumberLiteral && source.flags & TypeFlags.FreshLiteral) {
8789
8788
source = (<LiteralType>source).regularType;
8790
8789
}
@@ -8816,32 +8815,39 @@ namespace ts {
8816
8815
}
8817
8816
}
8818
8817
8818
+ if (!(source.flags & TypeFlags.UnionOrIntersection) &&
8819
+ !(target.flags & TypeFlags.Union) &&
8820
+ !isIntersectionConstituent &&
8821
+ source !== globalObjectType &&
8822
+ getPropertiesOfType(source).length > 0 &&
8823
+ isWeakType(target) &&
8824
+ !hasCommonProperties(source, target)) {
8825
+ if (reportErrors) {
8826
+ reportError(Diagnostics.Type_0_has_no_properties_in_common_with_type_1, typeToString(source), typeToString(target));
8827
+ }
8828
+ return Ternary.False;
8829
+ }
8830
+
8831
+ let result = Ternary.False;
8819
8832
const saveErrorInfo = errorInfo;
8833
+ const saveIsIntersectionConstituent = isIntersectionConstituent;
8834
+ isIntersectionConstituent = false;
8820
8835
8821
8836
// Note that these checks are specifically ordered to produce correct results. In particular,
8822
8837
// we need to deconstruct unions before intersections (because unions are always at the top),
8823
8838
// and we need to handle "each" relations before "some" relations for the same kind of type.
8824
8839
if (source.flags & TypeFlags.Union) {
8825
- if (relation === comparableRelation) {
8826
- result = someTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive));
8827
- }
8828
- else {
8829
- result = eachTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive));
8830
- }
8831
- if (result) {
8832
- return result;
8833
- }
8840
+ result = relation === comparableRelation ?
8841
+ someTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive)) :
8842
+ eachTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive));
8834
8843
}
8835
8844
else {
8836
8845
if (target.flags & TypeFlags.Union) {
8837
- if (result = typeRelatedToSomeType(source, <UnionType>target, reportErrors && !(source.flags & TypeFlags.Primitive) && !(target.flags & TypeFlags.Primitive))) {
8838
- return result;
8839
- }
8846
+ result = typeRelatedToSomeType(source, <UnionType>target, reportErrors && !(source.flags & TypeFlags.Primitive) && !(target.flags & TypeFlags.Primitive));
8840
8847
}
8841
8848
else if (target.flags & TypeFlags.Intersection) {
8842
- if (result = typeRelatedToEachType(source, target as IntersectionType, reportErrors)) {
8843
- return result;
8844
- }
8849
+ isIntersectionConstituent = true;
8850
+ result = typeRelatedToEachType(source, target as IntersectionType, reportErrors);
8845
8851
}
8846
8852
else if (source.flags & TypeFlags.Intersection) {
8847
8853
// Check to see if any constituents of the intersection are immediately related to the target.
@@ -8857,20 +8863,18 @@ namespace ts {
8857
8863
//
8858
8864
// - For a primitive type or type parameter (such as 'number = A & B') there is no point in
8859
8865
// breaking the intersection apart.
8860
- if (result = someTypeRelatedToType(<IntersectionType>source, target, /*reportErrors*/ false)) {
8861
- return result;
8862
- }
8866
+ result = someTypeRelatedToType(<IntersectionType>source, target, /*reportErrors*/ false);
8863
8867
}
8864
-
8865
- if (source.flags & TypeFlags.StructuredOrTypeVariable || target.flags & TypeFlags.StructuredOrTypeVariable) {
8868
+ if (!result && (source.flags & TypeFlags.StructuredOrTypeVariable || target.flags & TypeFlags.StructuredOrTypeVariable)) {
8866
8869
if (result = recursiveTypeRelatedTo(source, target, reportErrors)) {
8867
8870
errorInfo = saveErrorInfo;
8868
- return result;
8869
8871
}
8870
8872
}
8871
8873
}
8872
8874
8873
- if (reportErrors) {
8875
+ isIntersectionConstituent = saveIsIntersectionConstituent;
8876
+
8877
+ if (!result && reportErrors) {
8874
8878
if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Primitive) {
8875
8879
tryElaborateErrorsForPrimitivesAndObjects(source, target);
8876
8880
}
@@ -8879,7 +8883,7 @@ namespace ts {
8879
8883
}
8880
8884
reportRelationError(headMessage, source, target);
8881
8885
}
8882
- return Ternary.False ;
8886
+ return result ;
8883
8887
}
8884
8888
8885
8889
function isIdenticalTo(source: Type, target: Type): Ternary {
@@ -8981,39 +8985,14 @@ namespace ts {
8981
8985
function typeRelatedToEachType(source: Type, target: IntersectionType, reportErrors: boolean): Ternary {
8982
8986
let result = Ternary.True;
8983
8987
const targetTypes = target.types;
8984
- const saveDisableWeakTypeCheckingForIntersectionConstituents = disableWeakTypeCheckingForIntersectionConstituents;
8985
- disableWeakTypeCheckingForIntersectionConstituents = true;
8986
8988
for (const targetType of targetTypes) {
8987
8989
const related = isRelatedTo(source, targetType, reportErrors);
8988
8990
if (!related) {
8989
- disableWeakTypeCheckingForIntersectionConstituents = saveDisableWeakTypeCheckingForIntersectionConstituents;
8990
8991
return Ternary.False;
8991
8992
}
8992
8993
result &= related;
8993
8994
}
8994
- disableWeakTypeCheckingForIntersectionConstituents = saveDisableWeakTypeCheckingForIntersectionConstituents;
8995
- return reportAssignmentToWeakIntersection(source, target, reportErrors) ? Ternary.False : result;
8996
- }
8997
-
8998
- /**
8999
- * An intersection is weak if all of its constituents are weak. Report an error on assignment to a weak intersection
9000
- * of a type that doesn't share any property names with it.
9001
- *
9002
- * Note: This function could create an anonymous type of the flattened intersection properties and call isRelatedTo,
9003
- * but this makes React's already-bad weak type errors even more confusing.
9004
- */
9005
- function reportAssignmentToWeakIntersection(source: Type, target: IntersectionType, reportErrors: boolean) {
9006
- const needsWeakTypeCheck = source !== globalObjectType && getPropertiesOfType(source).length > 0 && every(target.types, isWeakType);
9007
- if (!needsWeakTypeCheck) {
9008
- return false;
9009
- }
9010
- const hasSharedProperty = forEach(
9011
- getPropertiesOfType(source),
9012
- p => isKnownProperty(target, p.name, /*isComparingJsxAttributes*/ false));
9013
- if (!hasSharedProperty && reportErrors) {
9014
- reportError(Diagnostics.Weak_type_0_has_no_properties_in_common_with_1, typeToString(target), typeToString(source));
9015
- }
9016
- return !hasSharedProperty;
8995
+ return result;
9017
8996
}
9018
8997
9019
8998
function someTypeRelatedToType(source: UnionOrIntersectionType, target: Type, reportErrors: boolean): Ternary {
@@ -9303,13 +9282,8 @@ namespace ts {
9303
9282
let result = Ternary.True;
9304
9283
const properties = getPropertiesOfObjectType(target);
9305
9284
const requireOptionalProperties = relation === subtypeRelation && !(getObjectFlags(source) & ObjectFlags.ObjectLiteral);
9306
- let foundMatchingProperty = !isWeakType(target);
9307
9285
for (const targetProp of properties) {
9308
9286
const sourceProp = getPropertyOfType(source, targetProp.name);
9309
- if (sourceProp) {
9310
- foundMatchingProperty = true;
9311
- }
9312
-
9313
9287
if (sourceProp !== targetProp) {
9314
9288
if (!sourceProp) {
9315
9289
if (!(targetProp.flags & SymbolFlags.Optional) || requireOptionalProperties) {
@@ -9359,10 +9333,7 @@ namespace ts {
9359
9333
}
9360
9334
return Ternary.False;
9361
9335
}
9362
- const saveDisableWeakTypeCheckingForIntersectionConstituents = disableWeakTypeCheckingForIntersectionConstituents;
9363
- disableWeakTypeCheckingForIntersectionConstituents = false;
9364
9336
const related = isRelatedTo(getTypeOfSymbol(sourceProp), getTypeOfSymbol(targetProp), reportErrors);
9365
- disableWeakTypeCheckingForIntersectionConstituents = saveDisableWeakTypeCheckingForIntersectionConstituents;
9366
9337
if (!related) {
9367
9338
if (reportErrors) {
9368
9339
reportError(Diagnostics.Types_of_property_0_are_incompatible, symbolToString(targetProp));
@@ -9388,31 +9359,35 @@ namespace ts {
9388
9359
}
9389
9360
}
9390
9361
}
9391
- if (!foundMatchingProperty &&
9392
- !disableWeakTypeCheckingForIntersectionConstituents &&
9393
- source !== globalObjectType &&
9394
- getPropertiesOfType(source).length > 0) {
9395
- if (reportErrors) {
9396
- reportError(Diagnostics.Weak_type_0_has_no_properties_in_common_with_1, typeToString(target), typeToString(source));
9397
- }
9398
- return Ternary.False;
9399
- }
9400
9362
return result;
9401
9363
}
9402
9364
9403
9365
/**
9404
9366
* A type is 'weak' if it is an object type with at least one optional property
9405
9367
* and no required properties, call/construct signatures or index signatures
9406
9368
*/
9407
- function isWeakType(type: Type) {
9408
- const props = getPropertiesOfType(type);
9409
- return type.flags & TypeFlags.Object &&
9410
- props.length > 0 &&
9411
- every(props, p => !!(p.flags & SymbolFlags.Optional)) &&
9412
- !getSignaturesOfType(type, SignatureKind.Call).length &&
9413
- !getSignaturesOfType(type, SignatureKind.Construct).length &&
9414
- !getIndexTypeOfType(type, IndexKind.String) &&
9415
- !getIndexTypeOfType(type, IndexKind.Number);
9369
+ function isWeakType(type: Type): boolean {
9370
+ if (type.flags & TypeFlags.Object) {
9371
+ const resolved = resolveStructuredTypeMembers(<ObjectType>type);
9372
+ return resolved.callSignatures.length === 0 && resolved.constructSignatures.length === 0 &&
9373
+ !resolved.stringIndexInfo && !resolved.numberIndexInfo &&
9374
+ resolved.properties.length > 0 &&
9375
+ every(resolved.properties, p => !!(p.flags & SymbolFlags.Optional));
9376
+ }
9377
+ if (type.flags & TypeFlags.Intersection) {
9378
+ return every((<IntersectionType>type).types, isWeakType);
9379
+ }
9380
+ return false;
9381
+ }
9382
+
9383
+ function hasCommonProperties(source: Type, target: Type) {
9384
+ const isComparingJsxAttributes = !!(source.flags & TypeFlags.JsxAttributes);
9385
+ for (const prop of getPropertiesOfType(source)) {
9386
+ if (isKnownProperty(target, prop.name, isComparingJsxAttributes)) {
9387
+ return true;
9388
+ }
9389
+ }
9390
+ return false;
9416
9391
}
9417
9392
9418
9393
function propertiesIdenticalTo(source: Type, target: Type): Ternary {
0 commit comments