From 876dbe86ee17b8521f6535739a01fe489d768a26 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Mon, 9 Jan 2017 08:53:10 -0800 Subject: [PATCH] Omit class methods from spreads. Others stay. Previously, all methods were omitted except those from the object literal that contained the spread. This gets rid of the ugly third argument to `getSpreadType`. It also fixes a bug that arose from removing the spread type late in the development of object spread; methods from the left-hand-side of a multi-spread object literal were not removed. The spread type code normalised spreads so the left-hand is never an object, but that code was removed. --- src/compiler/checker.ts | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 879be1c6fbf..d33ce374736 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6241,7 +6241,7 @@ namespace ts { * this function should be called in a left folding style, with left = previous result of getSpreadType * and right = the new element to be spread. */ - function getSpreadType(left: Type, right: Type, isFromObjectLiteral: boolean): Type { + function getSpreadType(left: Type, right: Type): Type { if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) { return anyType; } @@ -6254,10 +6254,10 @@ namespace ts { return left; } if (left.flags & TypeFlags.Union) { - return mapType(left, t => getSpreadType(t, right, isFromObjectLiteral)); + return mapType(left, t => getSpreadType(t, right)); } if (right.flags & TypeFlags.Union) { - return mapType(right, t => getSpreadType(left, t, isFromObjectLiteral)); + return mapType(right, t => getSpreadType(left, t)); } const members = createMap(); @@ -6276,18 +6276,18 @@ namespace ts { for (const rightProp of getPropertiesOfType(right)) { // we approximate own properties as non-methods plus methods that are inside the object literal - const isOwnProperty = !(rightProp.flags & SymbolFlags.Method) || isFromObjectLiteral; const isSetterWithoutGetter = rightProp.flags & SymbolFlags.SetAccessor && !(rightProp.flags & SymbolFlags.GetAccessor); if (getDeclarationModifierFlagsFromSymbol(rightProp) & (ModifierFlags.Private | ModifierFlags.Protected)) { skippedPrivateMembers[rightProp.name] = true; } - else if (isOwnProperty && !isSetterWithoutGetter) { + else if (!isClassMethod(rightProp) && !isSetterWithoutGetter) { members[rightProp.name] = rightProp; } } for (const leftProp of getPropertiesOfType(left)) { if (leftProp.flags & SymbolFlags.SetAccessor && !(leftProp.flags & SymbolFlags.GetAccessor) - || leftProp.name in skippedPrivateMembers) { + || leftProp.name in skippedPrivateMembers + || isClassMethod(leftProp)) { continue; } if (leftProp.name in members) { @@ -6312,6 +6312,10 @@ namespace ts { return createAnonymousType(undefined, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo); } + function isClassMethod(prop: Symbol) { + return prop.flags & SymbolFlags.Method && find(prop.declarations, decl => isClassLike(decl.parent)); + } + function createLiteralType(flags: TypeFlags, text: string) { const type = createType(flags); type.text = text; @@ -11658,7 +11662,7 @@ namespace ts { checkExternalEmitHelpers(memberDecl, ExternalEmitHelpers.Assign); } if (propertiesArray.length > 0) { - spread = getSpreadType(spread, createObjectLiteralType(), /*isFromObjectLiteral*/ true); + spread = getSpreadType(spread, createObjectLiteralType()); propertiesArray = []; propertiesTable = createMap(); hasComputedStringProperty = false; @@ -11670,7 +11674,7 @@ namespace ts { error(memberDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types); return unknownType; } - spread = getSpreadType(spread, type, /*isFromObjectLiteral*/ false); + spread = getSpreadType(spread, type); offset = i + 1; continue; } @@ -11715,7 +11719,7 @@ namespace ts { if (spread !== emptyObjectType) { if (propertiesArray.length > 0) { - spread = getSpreadType(spread, createObjectLiteralType(), /*isFromObjectLiteral*/ true); + spread = getSpreadType(spread, createObjectLiteralType()); } if (spread.flags & TypeFlags.Object) { // only set the symbol and flags if this is a (fresh) object type