-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixes rename for destructuring, named imports and default imports #7945
Changes from 15 commits
ace2285
01ca100
168d106
6d43c02
ad916ab
2e44bcc
a405f28
92622bf
f7ca439
9e77730
9e82646
7a09e2f
529bdd4
9496146
edd0989
958a6a4
c492fc6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -83,6 +83,7 @@ namespace ts { | |
getShorthandAssignmentValueSymbol, | ||
getExportSpecifierLocalTargetSymbol, | ||
getTypeAtLocation: getTypeOfNode, | ||
getTypeOfArrayLiteralOrObjectLiteralDestructuringAssignment, | ||
typeToString, | ||
getSymbolDisplayBuilder, | ||
symbolToString, | ||
|
@@ -11797,39 +11798,43 @@ namespace ts { | |
function checkObjectLiteralAssignment(node: ObjectLiteralExpression, sourceType: Type, contextualMapper?: TypeMapper): Type { | ||
const properties = node.properties; | ||
for (const p of properties) { | ||
if (p.kind === SyntaxKind.PropertyAssignment || p.kind === SyntaxKind.ShorthandPropertyAssignment) { | ||
const name = <PropertyName>(<PropertyAssignment>p).name; | ||
if (name.kind === SyntaxKind.ComputedPropertyName) { | ||
checkComputedPropertyName(<ComputedPropertyName>name); | ||
} | ||
if (isComputedNonLiteralName(name)) { | ||
continue; | ||
} | ||
checkObjectLiteralDestructuringPropertyAssignment(sourceType, p, contextualMapper); | ||
} | ||
return sourceType; | ||
} | ||
|
||
const text = getTextOfPropertyName(name); | ||
const type = isTypeAny(sourceType) | ||
? sourceType | ||
: getTypeOfPropertyOfType(sourceType, text) || | ||
isNumericLiteralName(text) && getIndexTypeOfType(sourceType, IndexKind.Number) || | ||
getIndexTypeOfType(sourceType, IndexKind.String); | ||
if (type) { | ||
if (p.kind === SyntaxKind.ShorthandPropertyAssignment) { | ||
checkDestructuringAssignment(<ShorthandPropertyAssignment>p, type); | ||
} | ||
else { | ||
// non-shorthand property assignments should always have initializers | ||
checkDestructuringAssignment((<PropertyAssignment>p).initializer, type); | ||
} | ||
function checkObjectLiteralDestructuringPropertyAssignment(objectLiteralType: Type, property: ObjectLiteralElement, contextualMapper?: TypeMapper) { | ||
if (property.kind === SyntaxKind.PropertyAssignment || property.kind === SyntaxKind.ShorthandPropertyAssignment) { | ||
const name = <PropertyName>(<PropertyAssignment>property).name; | ||
if (name.kind === SyntaxKind.ComputedPropertyName) { | ||
checkComputedPropertyName(<ComputedPropertyName>name); | ||
} | ||
if (isComputedNonLiteralName(name)) { | ||
return undefined; | ||
} | ||
|
||
const text = getTextOfPropertyName(name); | ||
const type = isTypeAny(objectLiteralType) | ||
? objectLiteralType | ||
: getTypeOfPropertyOfType(objectLiteralType, text) || | ||
isNumericLiteralName(text) && getIndexTypeOfType(objectLiteralType, IndexKind.Number) || | ||
getIndexTypeOfType(objectLiteralType, IndexKind.String); | ||
if (type) { | ||
if (property.kind === SyntaxKind.ShorthandPropertyAssignment) { | ||
return checkDestructuringAssignment(<ShorthandPropertyAssignment>property, type); | ||
} | ||
else { | ||
error(name, Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, typeToString(sourceType), declarationNameToString(name)); | ||
// non-shorthand property assignments should always have initializers | ||
return checkDestructuringAssignment((<PropertyAssignment>property).initializer, type); | ||
} | ||
} | ||
else { | ||
error(p, Diagnostics.Property_assignment_expected); | ||
error(name, Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, typeToString(objectLiteralType), declarationNameToString(name)); | ||
} | ||
} | ||
return sourceType; | ||
else { | ||
error(property, Diagnostics.Property_assignment_expected); | ||
} | ||
} | ||
|
||
function checkArrayLiteralAssignment(node: ArrayLiteralExpression, sourceType: Type, contextualMapper?: TypeMapper): Type { | ||
|
@@ -11839,44 +11844,51 @@ namespace ts { | |
const elementType = checkIteratedTypeOrElementType(sourceType, node, /*allowStringInput*/ false) || unknownType; | ||
const elements = node.elements; | ||
for (let i = 0; i < elements.length; i++) { | ||
const e = elements[i]; | ||
if (e.kind !== SyntaxKind.OmittedExpression) { | ||
if (e.kind !== SyntaxKind.SpreadElementExpression) { | ||
const propName = "" + i; | ||
const type = isTypeAny(sourceType) | ||
? sourceType | ||
: isTupleLikeType(sourceType) | ||
? getTypeOfPropertyOfType(sourceType, propName) | ||
: elementType; | ||
if (type) { | ||
checkDestructuringAssignment(e, type, contextualMapper); | ||
checkArrayLiteralDestructuringElementAssignment(node, sourceType, i, elementType, contextualMapper); | ||
} | ||
return sourceType; | ||
} | ||
|
||
function checkArrayLiteralDestructuringElementAssignment(node: ArrayLiteralExpression, sourceType: Type, | ||
elementIndex: number, elementType: Type, contextualMapper?: TypeMapper) { | ||
const elements = node.elements; | ||
const element = elements[elementIndex]; | ||
if (element.kind !== SyntaxKind.OmittedExpression) { | ||
if (element.kind !== SyntaxKind.SpreadElementExpression) { | ||
const propName = "" + elementIndex; | ||
const type = isTypeAny(sourceType) | ||
? sourceType | ||
: isTupleLikeType(sourceType) | ||
? getTypeOfPropertyOfType(sourceType, propName) | ||
: elementType; | ||
if (type) { | ||
return checkDestructuringAssignment(element, type, contextualMapper); | ||
} | ||
else { | ||
if (isTupleType(sourceType)) { | ||
error(element, Diagnostics.Tuple_type_0_with_length_1_cannot_be_assigned_to_tuple_with_length_2, typeToString(sourceType), (<TupleType>sourceType).elementTypes.length, elements.length); | ||
} | ||
else { | ||
if (isTupleType(sourceType)) { | ||
error(e, Diagnostics.Tuple_type_0_with_length_1_cannot_be_assigned_to_tuple_with_length_2, typeToString(sourceType), (<TupleType>sourceType).elementTypes.length, elements.length); | ||
} | ||
else { | ||
error(e, Diagnostics.Type_0_has_no_property_1, typeToString(sourceType), propName); | ||
} | ||
error(element, Diagnostics.Type_0_has_no_property_1, typeToString(sourceType), propName); | ||
} | ||
} | ||
} | ||
else { | ||
if (elementIndex < elements.length - 1) { | ||
error(element, Diagnostics.A_rest_element_must_be_last_in_an_array_destructuring_pattern); | ||
} | ||
else { | ||
if (i < elements.length - 1) { | ||
error(e, Diagnostics.A_rest_element_must_be_last_in_an_array_destructuring_pattern); | ||
const restExpression = (<SpreadElementExpression>element).expression; | ||
if (restExpression.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>restExpression).operatorToken.kind === SyntaxKind.EqualsToken) { | ||
error((<BinaryExpression>restExpression).operatorToken, Diagnostics.A_rest_element_cannot_have_an_initializer); | ||
} | ||
else { | ||
const restExpression = (<SpreadElementExpression>e).expression; | ||
if (restExpression.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>restExpression).operatorToken.kind === SyntaxKind.EqualsToken) { | ||
error((<BinaryExpression>restExpression).operatorToken, Diagnostics.A_rest_element_cannot_have_an_initializer); | ||
} | ||
else { | ||
checkDestructuringAssignment(restExpression, createArrayType(elementType), contextualMapper); | ||
} | ||
return checkDestructuringAssignment(restExpression, createArrayType(elementType), contextualMapper); | ||
} | ||
} | ||
} | ||
} | ||
return sourceType; | ||
return undefined; | ||
} | ||
|
||
function checkDestructuringAssignment(exprOrAssignment: Expression | ShorthandPropertyAssignment, sourceType: Type, contextualMapper?: TypeMapper): Type { | ||
|
@@ -16549,6 +16561,40 @@ namespace ts { | |
return unknownType; | ||
} | ||
|
||
// Gets the type of object literal or array literal of destructuring assignment. | ||
// { a } from | ||
// for ( { a } of elems) { | ||
// } | ||
// [ a ] from | ||
// [a] = [ some array ...] | ||
function getTypeOfArrayLiteralOrObjectLiteralDestructuringAssignment(expr: Expression): Type { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is not this the same as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Its kind of higher level and gets the type of binding patterns object literal or array literal from binding pattern assignment. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we should then change the entry point to return a targetSymbol for a bindingPattern instead of a type. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @mhegazy done. |
||
// If this is from "for of" | ||
// for ( { a } of elems) { | ||
// } | ||
if (expr.parent.kind === SyntaxKind.ForOfStatement) { | ||
const iteratedType = checkRightHandSideOfForOf((<ForOfStatement>expr.parent).expression); | ||
return checkDestructuringAssignment(expr, iteratedType || unknownType); | ||
} | ||
// If this is from "for" initializer | ||
// for ({a } = elems[0];.....) { } | ||
if (expr.parent.kind === SyntaxKind.BinaryExpression) { | ||
const iteratedType = checkExpression((<BinaryExpression>expr.parent).right); | ||
return checkDestructuringAssignment(expr, iteratedType || unknownType); | ||
} | ||
// If this is from nested object binding pattern | ||
// for ({ skills: { primary, secondary } } = multiRobot, i = 0; i < 1; i++) { | ||
if (expr.parent.kind === SyntaxKind.PropertyAssignment) { | ||
const typeOfParentObjectLiteral = getTypeOfArrayLiteralOrObjectLiteralDestructuringAssignment(<Expression>expr.parent.parent); | ||
return checkObjectLiteralDestructuringPropertyAssignment(typeOfParentObjectLiteral || unknownType, <ObjectLiteralElement>expr.parent); | ||
} | ||
// Array literal assignment - array destructuring pattern | ||
Debug.assert(expr.parent.kind === SyntaxKind.ArrayLiteralExpression); | ||
// [{ property1: p1, property2 }] = elems; | ||
const typeOfArrayLiteral = getTypeOfArrayLiteralOrObjectLiteralDestructuringAssignment(<Expression>expr.parent); | ||
const elementType = checkIteratedTypeOrElementType(typeOfArrayLiteral || unknownType, expr.parent, /*allowStringInput*/ false) || unknownType; | ||
return checkArrayLiteralDestructuringElementAssignment(<ArrayLiteralExpression>expr.parent, typeOfArrayLiteral, | ||
indexOf((<ArrayLiteralExpression>expr.parent).elements, expr), elementType || unknownType); | ||
} | ||
|
||
function getTypeOfExpression(expr: Expression): Type { | ||
if (isRightSideOfQualifiedNameOrPropertyAccess(expr)) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this implicitly return
undefined
? Invert the conditions here to reduce nesting and make the returns explicit.