From aa269800c004f1a77f5aa86a5dea8a1093a9465a Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 13 Jul 2015 10:20:16 -0700 Subject: [PATCH] Addressing CR feedback --- src/compiler/checker.ts | 14 +++++++++++--- src/compiler/types.ts | 3 +++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a9b39162b81..ca765e38768 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3352,6 +3352,10 @@ namespace ts { return undefined; } + // Check if a property with the given name is known anywhere in the given type. In an object + // type, a property is considered known if the object type is empty, if it has any index + // signatures, or if the property is actually declared in the type. In a union or intersection + // type, a property is considered known if it is known in any constituent type. function isKnownProperty(type: Type, name: string): boolean { if (type.flags & TypeFlags.ObjectType) { var resolved = resolveStructuredTypeMembers(type); @@ -4526,13 +4530,17 @@ namespace ts { } } - if (relation === assignableRelation && source.flags & TypeFlags.ObjectLiteral && source.flags & TypeFlags.FreshObjectLiteral) { - if (hasExcessProperties(source, target, reportErrors)) { + if (relation !== identityRelation && source.flags & TypeFlags.FreshObjectLiteral) { + if (hasExcessProperties(source, target, reportErrors)) { if (reportErrors) { reportRelationError(headMessage, source, target); } return Ternary.False; } + // Above we check for excess properties with respect to the entire target type. When union + // and intersection types are further deconstructed on the target side, we don't want to + // make the check again (as it might fail for a partial target type). Therefore we obtain + // the regular source type and proceed with that. source = getRegularTypeOfObjectLiteral(source); } @@ -4619,7 +4627,7 @@ namespace ts { return Ternary.False; } - function hasExcessProperties(source: ObjectType, target: Type, reportErrors: boolean): boolean { + function hasExcessProperties(source: FreshObjectLiteralType, target: Type, reportErrors: boolean): boolean { for (let prop of getPropertiesOfObjectType(source)) { if (!isKnownProperty(target, prop.name)) { if (reportErrors) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index d23f2f69bf9..45b9699c117 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1842,6 +1842,9 @@ namespace ts { } /* @internal */ + // Object literals are initially marked fresh. Freshness disappears following an assignment, + // before a type assertion, or when when an object literal's type is widened. The regular + // version of a fresh type is identical except for the TypeFlags.FreshObjectLiteral flag. export interface FreshObjectLiteralType extends ResolvedType { regularType: ResolvedType; // Regular version of fresh type }