mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 21:53:42 -06:00
Fixed a false positive related to binding patterns and spread expressions (#49684)
* Fixed a false positive related to binding patterns and spread expressions * Improve ancestor lookup when checking if an expression is spread into an object * Fixed ancestor lookup for more node types * Remove equality check for contextual types * Reformat code * Use `isWithinSpreadAssignment` flag + `objectsWithinSpread` cache instead of ancestor traversal * Revert "Use `isWithinSpreadAssignment` flag + `objectsWithinSpread` cache instead of ancestor traversal" This reverts commit be387e3bbf8a5cce2bc4c31fd77b061ea6cf8e0b. * Expand on the existing comment
This commit is contained in:
parent
71e8529228
commit
0e17dc7769
@ -28163,16 +28163,31 @@ namespace ts {
|
||||
// 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 && node.parent.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);
|
||||
// literal handle it instead. Note that this might require full traversal to the root pattern's parent
|
||||
// as it's the guaranteed to be the common ancestor of the pattern node and the current object node.
|
||||
// It's not possible to check if the immediate parent node is a spread assignment
|
||||
// since the type flows in non-obvious ways through conditional expressions, IIFEs and more.
|
||||
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);
|
||||
}
|
||||
propertiesTable.set(prop.escapedName, prop);
|
||||
propertiesArray.push(prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,23 @@
|
||||
=== tests/cases/compiler/spreadExpressionContainingObjectExpressionContextualType.ts ===
|
||||
// repro #49585
|
||||
|
||||
const { value } = (() => ({
|
||||
>value : Symbol(value, Decl(spreadExpressionContainingObjectExpressionContextualType.ts, 2, 7))
|
||||
|
||||
value: "",
|
||||
>value : Symbol(value, Decl(spreadExpressionContainingObjectExpressionContextualType.ts, 2, 27))
|
||||
|
||||
...(true ? {} : {}),
|
||||
}))();
|
||||
|
||||
// repro 49684#discussion_r920545763
|
||||
|
||||
const { value2 } = {
|
||||
>value2 : Symbol(value2, Decl(spreadExpressionContainingObjectExpressionContextualType.ts, 9, 7))
|
||||
|
||||
value2: "",
|
||||
>value2 : Symbol(value2, Decl(spreadExpressionContainingObjectExpressionContextualType.ts, 9, 20))
|
||||
|
||||
...(() => true ? {} : {})(),
|
||||
};
|
||||
|
||||
@ -0,0 +1,45 @@
|
||||
=== tests/cases/compiler/spreadExpressionContainingObjectExpressionContextualType.ts ===
|
||||
// repro #49585
|
||||
|
||||
const { value } = (() => ({
|
||||
>value : string
|
||||
>(() => ({ value: "", ...(true ? {} : {}),}))() : { value: string; }
|
||||
>(() => ({ value: "", ...(true ? {} : {}),})) : () => { value: string; }
|
||||
>() => ({ value: "", ...(true ? {} : {}),}) : () => { value: string; }
|
||||
>({ value: "", ...(true ? {} : {}),}) : { value: string; }
|
||||
>{ value: "", ...(true ? {} : {}),} : { value: string; }
|
||||
|
||||
value: "",
|
||||
>value : string
|
||||
>"" : ""
|
||||
|
||||
...(true ? {} : {}),
|
||||
>(true ? {} : {}) : {}
|
||||
>true ? {} : {} : {}
|
||||
>true : true
|
||||
>{} : {}
|
||||
>{} : {}
|
||||
|
||||
}))();
|
||||
|
||||
// repro 49684#discussion_r920545763
|
||||
|
||||
const { value2 } = {
|
||||
>value2 : string
|
||||
>{ value2: "", ...(() => true ? {} : {})(),} : { value2: string; }
|
||||
|
||||
value2: "",
|
||||
>value2 : string
|
||||
>"" : ""
|
||||
|
||||
...(() => true ? {} : {})(),
|
||||
>(() => true ? {} : {})() : {}
|
||||
>(() => true ? {} : {}) : () => {}
|
||||
>() => true ? {} : {} : () => {}
|
||||
>true ? {} : {} : {}
|
||||
>true : true
|
||||
>{} : {}
|
||||
>{} : {}
|
||||
|
||||
};
|
||||
|
||||
@ -0,0 +1,15 @@
|
||||
// @noEmit: true
|
||||
|
||||
// repro #49585
|
||||
|
||||
const { value } = (() => ({
|
||||
value: "",
|
||||
...(true ? {} : {}),
|
||||
}))();
|
||||
|
||||
// repro 49684#discussion_r920545763
|
||||
|
||||
const { value2 } = {
|
||||
value2: "",
|
||||
...(() => true ? {} : {})(),
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user