Skip to content

Commit 43811dd

Browse files
committed
Use getIndexedAccessType when computing destructured types
1 parent fecbdb6 commit 43811dd

File tree

2 files changed

+35
-92
lines changed

2 files changed

+35
-92
lines changed

src/compiler/checker.ts

Lines changed: 35 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -4827,21 +4827,13 @@ namespace ts {
48274827
mapType(parentType, t => sliceTupleType(<TupleTypeReference>t, index)) :
48284828
createArrayType(elementType);
48294829
}
4830+
else if (isArrayLikeType(parentType)) {
4831+
const indexType = getLiteralType(index);
4832+
const declaredType = getIndexedAccessType(parentType, indexType, createSyntheticExpression(declaration.name, indexType));
4833+
type = getFlowTypeOfReference(declaration, getConstraintForLocation(declaredType, declaration.name));
4834+
}
48304835
else {
4831-
// Use specific property type when parent is a tuple or numeric index type when parent is an array
4832-
const index = pattern.elements.indexOf(declaration);
4833-
type = everyType(parentType, isTupleLikeType) ?
4834-
getTupleElementType(parentType, index) || declaration.initializer && checkDeclarationInitializer(declaration) :
4835-
elementType;
4836-
if (!type) {
4837-
if (isTupleType(parentType)) {
4838-
error(declaration, Diagnostics.Tuple_type_0_with_length_1_cannot_be_assigned_to_tuple_with_length_2, typeToString(parentType), getTypeReferenceArity(<TypeReference>parentType), pattern.elements.length);
4839-
}
4840-
else {
4841-
error(declaration, Diagnostics.Type_0_has_no_property_1, typeToString(parentType), "" + index);
4842-
}
4843-
return errorType;
4844-
}
4836+
type = elementType;
48454837
}
48464838
}
48474839
// In strict null checking mode, if a default value of a non-undefined type is specified, remove
@@ -9523,7 +9515,7 @@ namespace ts {
95239515
return false;
95249516
}
95259517

9526-
function getPropertyTypeForIndexType(objectType: Type, indexType: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | undefined, cacheSymbol: boolean, missingType: Type) {
9518+
function getPropertyTypeForIndexType(objectType: Type, indexType: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | SyntheticExpression | undefined, cacheSymbol: boolean, missingType: Type) {
95279519
const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode : undefined;
95289520
const propName = isTypeUsableAsLateBoundName(indexType)
95299521
? getLateBoundNameFromType(indexType)
@@ -9626,7 +9618,7 @@ namespace ts {
96269618
return missingType;
96279619
}
96289620

9629-
function getIndexNodeForAccessExpression(accessNode: ElementAccessExpression | IndexedAccessTypeNode | PropertyName) {
9621+
function getIndexNodeForAccessExpression(accessNode: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | SyntheticExpression) {
96309622
return accessNode.kind === SyntaxKind.ElementAccessExpression
96319623
? accessNode.argumentExpression
96329624
: accessNode.kind === SyntaxKind.IndexedAccessType
@@ -9695,7 +9687,7 @@ namespace ts {
96959687
return type.simplified = type;
96969688
}
96979689

9698-
function getIndexedAccessType(objectType: Type, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode | PropertyName, missingType = accessNode ? errorType : unknownType): Type {
9690+
function getIndexedAccessType(objectType: Type, indexType: Type, accessNode?: ElementAccessExpression | IndexedAccessTypeNode | PropertyName | SyntheticExpression, missingType = accessNode ? errorType : unknownType): Type {
96999691
if (objectType === wildcardType || indexType === wildcardType) {
97009692
return wildcardType;
97019693
}
@@ -14628,7 +14620,7 @@ namespace ts {
1462814620
getAccessedPropertyName(source as PropertyAccessExpression | ElementAccessExpression) === getAccessedPropertyName(target) &&
1462914621
isMatchingReference((source as PropertyAccessExpression | ElementAccessExpression).expression, target.expression);
1463014622
case SyntaxKind.BindingElement:
14631-
if (target.kind === SyntaxKind.PropertyAccessExpression && (<PropertyAccessExpression>target).name.escapedText === getBindingElementNameText(<BindingElement>source)) {
14623+
if ((isPropertyAccessExpression(target) || isElementAccessExpression(target)) && getBindingElementNameText(<BindingElement>source) === getAccessedPropertyName(target)) {
1463214624
const ancestor = source.parent.parent;
1463314625
if (ancestor.kind === SyntaxKind.BindingElement) {
1463414626
return isMatchingReference(ancestor, (<PropertyAccessExpression>target).expression);
@@ -22010,21 +22002,17 @@ namespace ts {
2201022002
function checkObjectLiteralDestructuringPropertyAssignment(objectLiteralType: Type, property: ObjectLiteralElementLike, allProperties?: NodeArray<ObjectLiteralElementLike>, rightIsThis = false) {
2201122003
if (property.kind === SyntaxKind.PropertyAssignment || property.kind === SyntaxKind.ShorthandPropertyAssignment) {
2201222004
const name = property.name;
22013-
if (name.kind === SyntaxKind.ComputedPropertyName) {
22014-
checkComputedPropertyName(name);
22015-
}
22016-
if (isComputedNonLiteralName(name)) {
22017-
return undefined;
22018-
}
22019-
22020-
const type = getTypeOfObjectLiteralDestructuringProperty(objectLiteralType, name, property, rightIsThis);
22021-
if (type) {
22022-
// non-shorthand property assignments should always have initializers
22023-
return checkDestructuringAssignment(property.kind === SyntaxKind.ShorthandPropertyAssignment ? property : property.initializer, type);
22024-
}
22025-
else {
22026-
error(name, Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, typeToString(objectLiteralType), declarationNameToString(name));
22005+
const text = getTextOfPropertyName(name);
22006+
if (text) {
22007+
const prop = getPropertyOfType(objectLiteralType, text);
22008+
if (prop) {
22009+
markPropertyAsReferenced(prop, property, rightIsThis);
22010+
checkPropertyAccessibility(property, /*isSuper*/ false, objectLiteralType, prop);
22011+
}
2202722012
}
22013+
const exprType = getLiteralTypeFromPropertyName(name);
22014+
const type = getIndexedAccessType(objectLiteralType, exprType, name);
22015+
return checkDestructuringAssignment(property.kind === SyntaxKind.ShorthandPropertyAssignment ? property : property.initializer, type);
2202822016
}
2202922017
else if (property.kind === SyntaxKind.SpreadAssignment) {
2203022018
if (languageVersion < ScriptTarget.ESNext) {
@@ -22045,31 +22033,11 @@ namespace ts {
2204522033
}
2204622034
}
2204722035

22048-
function getTypeOfObjectLiteralDestructuringProperty(objectLiteralType: Type, name: PropertyName, property: PropertyAssignment | ShorthandPropertyAssignment, rightIsThis: boolean) {
22049-
if (isTypeAny(objectLiteralType)) {
22050-
return objectLiteralType;
22051-
}
22052-
22053-
let type: Type | undefined;
22054-
const text = getTextOfPropertyName(name);
22055-
if (text) { // TODO: GH#26379
22056-
const prop = getPropertyOfType(objectLiteralType, text);
22057-
if (prop) {
22058-
markPropertyAsReferenced(prop, property, rightIsThis);
22059-
checkPropertyAccessibility(property, /*isSuper*/ false, objectLiteralType, prop);
22060-
type = getTypeOfSymbol(prop);
22061-
}
22062-
type = type || (isNumericLiteralName(text) ? getIndexTypeOfType(objectLiteralType, IndexKind.Number) : undefined);
22063-
}
22064-
return type || getIndexTypeOfType(objectLiteralType, IndexKind.String);
22065-
}
22066-
2206722036
function checkArrayLiteralAssignment(node: ArrayLiteralExpression, sourceType: Type, checkMode?: CheckMode): Type {
2206822037
const elements = node.elements;
2206922038
if (languageVersion < ScriptTarget.ES2015 && compilerOptions.downlevelIteration) {
2207022039
checkExternalEmitHelpers(node, ExternalEmitHelpers.Read);
2207122040
}
22072-
2207322041
// This elementType will be used if the specific property corresponding to this index is not
2207422042
// present (aka the tuple element property). This call also checks that the parentType is in
2207522043
// fact an iterable or array (depending on target language).
@@ -22086,39 +22054,26 @@ namespace ts {
2208622054
const element = elements[elementIndex];
2208722055
if (element.kind !== SyntaxKind.OmittedExpression) {
2208822056
if (element.kind !== SyntaxKind.SpreadElement) {
22089-
const propName = "" + elementIndex as __String;
22090-
const type = isTypeAny(sourceType) ? sourceType :
22091-
everyType(sourceType, isTupleLikeType) ? getTupleElementType(sourceType, elementIndex) :
22057+
const indexType = getLiteralType(elementIndex);
22058+
const type = isArrayLikeType(sourceType) ?
22059+
getIndexedAccessType(sourceType, indexType, createSyntheticExpression(element, indexType)) :
2209222060
elementType;
22093-
if (type) {
22094-
return checkDestructuringAssignment(element, type, checkMode);
22095-
}
22096-
// We still need to check element expression here because we may need to set appropriate flag on the expression
22097-
// such as NodeCheckFlags.LexicalThis on "this"expression.
22098-
checkExpression(element);
22099-
if (isTupleType(sourceType)) {
22100-
error(element, Diagnostics.Tuple_type_0_with_length_1_cannot_be_assigned_to_tuple_with_length_2, typeToString(sourceType), getTypeReferenceArity(<TypeReference>sourceType), elements.length);
22101-
}
22102-
else {
22103-
error(element, Diagnostics.Type_0_has_no_property_1, typeToString(sourceType), propName as string);
22104-
}
22061+
return checkDestructuringAssignment(element, type, checkMode);
22062+
}
22063+
if (elementIndex < elements.length - 1) {
22064+
error(element, Diagnostics.A_rest_element_must_be_last_in_a_destructuring_pattern);
2210522065
}
2210622066
else {
22107-
if (elementIndex < elements.length - 1) {
22108-
error(element, Diagnostics.A_rest_element_must_be_last_in_a_destructuring_pattern);
22067+
const restExpression = (<SpreadElement>element).expression;
22068+
if (restExpression.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>restExpression).operatorToken.kind === SyntaxKind.EqualsToken) {
22069+
error((<BinaryExpression>restExpression).operatorToken, Diagnostics.A_rest_element_cannot_have_an_initializer);
2210922070
}
2211022071
else {
22111-
const restExpression = (<SpreadElement>element).expression;
22112-
if (restExpression.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>restExpression).operatorToken.kind === SyntaxKind.EqualsToken) {
22113-
error((<BinaryExpression>restExpression).operatorToken, Diagnostics.A_rest_element_cannot_have_an_initializer);
22114-
}
22115-
else {
22116-
checkGrammarForDisallowedTrailingComma(node.elements, Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma);
22117-
const type = everyType(sourceType, isTupleType) ?
22118-
mapType(sourceType, t => sliceTupleType(<TupleTypeReference>t, elementIndex)) :
22119-
createArrayType(elementType);
22120-
return checkDestructuringAssignment(restExpression, type, checkMode);
22121-
}
22072+
checkGrammarForDisallowedTrailingComma(node.elements, Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma);
22073+
const type = everyType(sourceType, isTupleType) ?
22074+
mapType(sourceType, t => sliceTupleType(<TupleTypeReference>t, elementIndex)) :
22075+
createArrayType(elementType);
22076+
return checkDestructuringAssignment(restExpression, type, checkMode);
2212222077
}
2212322078
}
2212422079
}

src/compiler/diagnosticMessages.json

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1636,14 +1636,6 @@
16361636
"category": "Error",
16371637
"code": 2458
16381638
},
1639-
"Type '{0}' has no property '{1}' and no string index signature.": {
1640-
"category": "Error",
1641-
"code": 2459
1642-
},
1643-
"Type '{0}' has no property '{1}'.": {
1644-
"category": "Error",
1645-
"code": 2460
1646-
},
16471639
"Type '{0}' is not an array type.": {
16481640
"category": "Error",
16491641
"code": 2461
@@ -1760,10 +1752,6 @@
17601752
"category": "Error",
17611753
"code": 2492
17621754
},
1763-
"Tuple type '{0}' with length '{1}' cannot be assigned to tuple with length '{2}'.": {
1764-
"category": "Error",
1765-
"code": 2493
1766-
},
17671755
"Using a string in a 'for...of' statement is only supported in ECMAScript 5 and higher.": {
17681756
"category": "Error",
17691757
"code": 2494

0 commit comments

Comments
 (0)