diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8ce3aa04046..f533cb52c17 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1005,6 +1005,9 @@ namespace ts { let lastFlowNode: FlowNode | undefined; let lastFlowNodeReachable: boolean; let flowTypeCache: Type[] | undefined; + let isWithinSpreadAssignment = false; + + const objectsWithinSpread = new WeakSet(); const emptyStringType = getStringLiteralType(""); const zeroType = getNumberLiteralType(0); @@ -28032,7 +28035,10 @@ namespace ts { hasComputedNumberProperty = false; hasComputedSymbolProperty = false; } + const isAlreadyWithinSpread = isWithinSpreadAssignment; + isWithinSpreadAssignment = true; const type = getReducedType(checkExpression(memberDecl.expression)); + isWithinSpreadAssignment = isAlreadyWithinSpread; if (isValidSpreadType(type)) { const mergedType = tryMergeUnionOfObjectTypeAndEmptyObject(type, inConstContext); if (allPropertiesTable) { @@ -28082,31 +28088,23 @@ namespace ts { propertiesArray.push(member); } + if (isWithinSpreadAssignment) { + objectsWithinSpread.add(node); + } + // If object literal is contextually typed by the implied type of a binding pattern, augment the result // type with those properties for which the binding pattern specifies a default value. // If the object literal is spread into another object literal, skip this step and let the top-level object // literal handle it instead. - if (contextualTypeHasPattern) { - const rootPatternParent = findAncestor(contextualType.pattern!.parent, n => - n.kind === SyntaxKind.VariableDeclaration || - n.kind === SyntaxKind.BinaryExpression || - n.kind === SyntaxKind.Parameter - ); - const spreadOrOutsideRootObject = findAncestor(node, n => - n === rootPatternParent || - n.kind === SyntaxKind.SpreadAssignment - )!; - - if (spreadOrOutsideRootObject.kind !== SyntaxKind.SpreadAssignment) { - for (const prop of getPropertiesOfType(contextualType)) { - if (!propertiesTable.get(prop.escapedName) && !getPropertyOfType(spread, prop.escapedName)) { - if (!(prop.flags & SymbolFlags.Optional)) { - error(prop.valueDeclaration || (prop as TransientSymbol).bindingElement, - Diagnostics.Initializer_provides_no_value_for_this_binding_element_and_the_binding_element_has_no_default_value); - } - propertiesTable.set(prop.escapedName, prop); - propertiesArray.push(prop); + if (contextualTypeHasPattern && !objectsWithinSpread.has(node)) { + for (const prop of getPropertiesOfType(contextualType)) { + if (!propertiesTable.get(prop.escapedName) && !getPropertyOfType(spread, prop.escapedName)) { + if (!(prop.flags & SymbolFlags.Optional)) { + error(prop.valueDeclaration || (prop as TransientSymbol).bindingElement, + Diagnostics.Initializer_provides_no_value_for_this_binding_element_and_the_binding_element_has_no_default_value); } + propertiesTable.set(prop.escapedName, prop); + propertiesArray.push(prop); } } }