Exclude generic types from weak object checks

This commit is contained in:
Anders Hejlsberg 2018-08-30 12:46:29 -07:00
parent d066e1e9e3
commit 316739e1c0

View File

@ -11185,13 +11185,10 @@ namespace ts {
}
}
if (relation !== comparableRelation &&
!(source.flags & TypeFlags.Union) &&
!(target.flags & TypeFlags.Union) &&
!isIntersectionConstituent &&
source !== globalObjectType &&
if (relation !== comparableRelation && !isIntersectionConstituent &&
source.flags & (TypeFlags.Primitive | TypeFlags.Object | TypeFlags.Intersection) && source !== globalObjectType &&
target.flags & (TypeFlags.Object | TypeFlags.Intersection) && isWeakType(target) &&
(getPropertiesOfType(source).length > 0 || typeHasCallOrConstructSignatures(source)) &&
isWeakType(target) &&
!hasCommonProperties(source, target)) {
if (reportErrors) {
const calls = getSignaturesOfType(source, SignatureKind.Call);
@ -12011,34 +12008,6 @@ namespace ts {
return result;
}
/**
* A type is 'weak' if it is an object type with at least one optional property
* and no required properties, call/construct signatures or index signatures
*/
function isWeakType(type: Type): boolean {
if (type.flags & TypeFlags.Object) {
const resolved = resolveStructuredTypeMembers(<ObjectType>type);
return resolved.callSignatures.length === 0 && resolved.constructSignatures.length === 0 &&
!resolved.stringIndexInfo && !resolved.numberIndexInfo &&
resolved.properties.length > 0 &&
every(resolved.properties, p => !!(p.flags & SymbolFlags.Optional));
}
if (type.flags & TypeFlags.Intersection) {
return every((<IntersectionType>type).types, isWeakType);
}
return false;
}
function hasCommonProperties(source: Type, target: Type) {
const isComparingJsxAttributes = !!(getObjectFlags(source) & ObjectFlags.JsxAttributes);
for (const prop of getPropertiesOfType(source)) {
if (isKnownProperty(target, prop.escapedName, isComparingJsxAttributes)) {
return true;
}
}
return false;
}
function propertiesIdenticalTo(source: Type, target: Type): Ternary {
if (!(source.flags & TypeFlags.Object && target.flags & TypeFlags.Object)) {
return Ternary.False;
@ -12283,6 +12252,34 @@ namespace ts {
}
}
/**
* A type is 'weak' if it is an object type with at least one optional property
* and no required properties, call/construct signatures or index signatures
*/
function isWeakType(type: Type): boolean {
if (type.flags & TypeFlags.Object) {
const resolved = resolveStructuredTypeMembers(<ObjectType>type);
return resolved.callSignatures.length === 0 && resolved.constructSignatures.length === 0 &&
!resolved.stringIndexInfo && !resolved.numberIndexInfo &&
resolved.properties.length > 0 &&
every(resolved.properties, p => !!(p.flags & SymbolFlags.Optional));
}
if (type.flags & TypeFlags.Intersection) {
return every((<IntersectionType>type).types, isWeakType);
}
return false;
}
function hasCommonProperties(source: Type, target: Type) {
const isComparingJsxAttributes = !!(getObjectFlags(source) & ObjectFlags.JsxAttributes);
for (const prop of getPropertiesOfType(source)) {
if (isKnownProperty(target, prop.escapedName, isComparingJsxAttributes)) {
return true;
}
}
return false;
}
// Return a type reference where the source type parameter is replaced with the target marker
// type, and flag the result as a marker type reference.
function getMarkerTypeReference(type: GenericType, source: TypeParameter, target: Type) {