From ce61b341599263f2caf68f34c644038f410ddb76 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Fri, 21 Oct 2016 10:53:19 -0700 Subject: [PATCH] Resolve all-object intersections inside spreads This means that getSpreadType will return an object type, even when spreading two intersections, as long as those intersections contain nothing but object types themselves. --- src/compiler/checker.ts | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index bf81d64ea06..5da7cc7e667 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5828,13 +5828,16 @@ namespace ts { types.push(rspread.right); return getSpreadType(types, symbol, aliasSymbol, aliasTypeArguments); } + if (right.flags & TypeFlags.Intersection) { + right = resolveObjectIntersection(right as IntersectionType); + } if (right.flags & TypeFlags.Union) { const spreads = map((right as UnionType).types, t => getSpreadType(types.slice().concat([t]), symbol, aliasSymbol, aliasTypeArguments)); return getUnionType(spreads, /*subtypeReduction*/ false, aliasSymbol, aliasTypeArguments); } const atBeginning = types.length === 0; - const left = getSpreadType(types, symbol, aliasSymbol, aliasTypeArguments); + let left = getSpreadType(types, symbol, aliasSymbol, aliasTypeArguments); if (right.flags & (TypeFlags.Primitive & ~TypeFlags.StringLike) || left.flags & TypeFlags.Any) { return left; } @@ -5853,6 +5856,9 @@ namespace ts { const simplified = getSpreadType([right, (left as SpreadType).right], symbol, aliasSymbol, aliasTypeArguments); return getSpreadType([(left as SpreadType).left, simplified], symbol, aliasSymbol, aliasTypeArguments); } + if (left.flags & TypeFlags.Intersection) { + left = resolveObjectIntersection(left as IntersectionType); + } if (left.flags & TypeFlags.Union) { const spreads = map((left as UnionType).types, t => getSpreadType(types.slice().concat([t, right]), symbol, aliasSymbol, aliasTypeArguments)); @@ -5917,6 +5923,20 @@ namespace ts { return spread; } + function resolveObjectIntersection(intersection: IntersectionType): IntersectionType | ResolvedType { + if (find(intersection.types, t => !(t.flags & TypeFlags.ObjectType && !couldContainTypeParameters(t)))) { + return intersection; + } + const properties = getPropertiesOfType(intersection); + const members = createMap(); + for (const property of properties) { + members[property.name] = property; + } + const stringIndex = getIndexInfoOfType(intersection, IndexKind.String); + const numberIndex = getIndexInfoOfType(intersection, IndexKind.Number); + return createAnonymousType(undefined, members, emptyArray, emptyArray, stringIndex, numberIndex); + } + function createLiteralType(flags: TypeFlags, text: string) { const type = createType(flags); type.text = text;