@@ -1660,25 +1660,34 @@ module ts {
16601660 return classType.typeParameters ? createTypeReference(<GenericType>classType, map(classType.typeParameters, _ => anyType)) : classType;
16611661 }
16621662
1663+ // Return the type of the given property in the given type, or undefined if no such property exists
16631664 function getTypeOfPropertyOfType(type: Type, name: string): Type {
16641665 var prop = getPropertyOfType(type, name);
16651666 return prop ? getTypeOfSymbol(prop) : undefined;
16661667 }
16671668
1669+ // Return the inferred type for a binding element
16681670 function getTypeForBindingElement(declaration: BindingElement): Type {
16691671 var pattern = <BindingPattern>declaration.parent;
16701672 var parentType = getTypeForVariableDeclaration(<VariableDeclaration>pattern.parent);
1673+ // If parent has the unknown (error) type, then so does this binding element
16711674 if (parentType === unknownType) {
16721675 return unknownType;
16731676 }
1677+ // If no type was specified or inferred for parent, or if the specified or inferred type is any,
1678+ // infer from the initializer of the binding element if one is present. Otherwise, go with the
1679+ // undefined or any type of the parent.
16741680 if (!parentType || parentType === anyType) {
16751681 if (declaration.initializer) {
16761682 return checkExpressionCached(declaration.initializer);
16771683 }
16781684 return parentType;
16791685 }
16801686 if (pattern.kind === SyntaxKind.ObjectBindingPattern) {
1687+ // Use explicitly specified property name ({ p: xxx } form), or otherwise the implied name ({ p } form)
16811688 var name = declaration.propertyName || <Identifier>declaration.name;
1689+ // Use type of the specified property, or otherwise, for a numeric name, the type of the numeric index signature,
1690+ // or otherwise the type of the string index signature.
16821691 var type = getTypeOfPropertyOfType(parentType, name.text) ||
16831692 isNumericName(name.text) && getIndexTypeOfType(parentType, IndexKind.Number) ||
16841693 getIndexTypeOfType(parentType, IndexKind.String);
@@ -1688,19 +1697,22 @@ module ts {
16881697 }
16891698 return type;
16901699 }
1700+ // For an array binding element the specified or inferred type of the parent must be assignable to any[]
16911701 if (!isTypeAssignableTo(parentType, anyArrayType)) {
16921702 error(pattern, Diagnostics.Type_0_is_not_an_array_type, typeToString(parentType));
16931703 return unknownType;
16941704 }
1705+ // Use specific property type when parent is a tuple or numeric index type when parent is an array
16951706 var propName = "" + indexOf(pattern.elements, declaration);
1696- var type = isTupleType ( parentType ) ? getTypeOfPropertyOfType ( parentType , propName ) : getIndexTypeOfType ( parentType , IndexKind . Number ) ;
1707+ var type = isTupleLikeType (parentType) ? getTypeOfPropertyOfType(parentType, propName) : getIndexTypeOfType(parentType, IndexKind.Number);
16971708 if (!type) {
16981709 error(declaration, Diagnostics.Type_0_has_no_property_1, typeToString(parentType), propName);
16991710 return unknownType;
17001711 }
17011712 return type;
17021713 }
17031714
1715+ // Return the inferred type for a variable, parameter, or property declaration
17041716 function getTypeForVariableDeclaration(declaration: VariableDeclaration): Type {
17051717 // A variable declared in a for..in statement is always of type any
17061718 if (declaration.parent.kind === SyntaxKind.ForInStatement) {
@@ -1732,15 +1744,17 @@ module ts {
17321744 if (declaration.initializer) {
17331745 return checkExpressionCached(declaration.initializer);
17341746 }
1735- // If it is a short-hand property assignment; Use the type of the identifier
1747+ // If it is a short-hand property assignment, use the type of the identifier
17361748 if (declaration.kind === SyntaxKind.ShorthandPropertyAssignment) {
1737- var type = checkIdentifier ( < Identifier > declaration . name ) ;
1738- return type
1749+ return checkIdentifier(<Identifier>declaration.name);
17391750 }
17401751 // No type specified and nothing can be inferred
17411752 return undefined;
17421753 }
17431754
1755+ // Return the type implied by a binding pattern element. This is the type of the initializer of the element if
1756+ // one is present. Otherwise, if the element is itself a binding pattern, it is the type implied by the binding
1757+ // pattern. Otherwise, it is the type any.
17441758 function getTypeFromBindingElement(element: BindingElement): Type {
17451759 if (element.initializer) {
17461760 return getWidenedType(checkExpressionCached(element.initializer));
@@ -1751,6 +1765,13 @@ module ts {
17511765 return anyType;
17521766 }
17531767
1768+ // Return the type implied by a binding pattern. This is the type implied purely by the binding pattern itself
1769+ // and without regard to its context (i.e. without regard any type annotation or initializer associated with the
1770+ // declaration in which the binding pattern is contained). For example, the implied type of [x, y] is [any, any]
1771+ // and the implied type of { x, y: z = 1 } is { x: any; y: number; }. The type implied by a binding pattern is
1772+ // used as the contextual type of an initializer associated with the binding pattern. Also, for a destructuring
1773+ // parameter with no type annotation or initializer, the type implied by the binding pattern becomes the type of
1774+ // the parameter.
17541775 function getTypeFromBindingPattern(pattern: BindingPattern): Type {
17551776 if (pattern.kind === SyntaxKind.ArrayBindingPattern) {
17561777 return createTupleType(map(pattern.elements, e => e.kind === SyntaxKind.OmittedExpression ? anyType : getTypeFromBindingElement(e)));
@@ -1766,14 +1787,28 @@ module ts {
17661787 return createAnonymousType(undefined, members, emptyArray, emptyArray, undefined, undefined);
17671788 }
17681789
1790+ // Return the type associated with a variable, parameter, or property declaration. In the simple case this is the type
1791+ // specified in a type annotation or inferred from an initializer. However, in the case of a destructuring declaration it
1792+ // is a bit more involved. For example:
1793+ //
1794+ // var [x, s = ""] = [1, "one"];
1795+ //
1796+ // Here, the array literal [1, "one"] is contextually typed by the type [any, string], which is the implied type of the
1797+ // binding pattern [x, s = ""]. Because the contextual type is a tuple type, the resulting type of [1, "one"] is the
1798+ // tuple type [number, string]. Thus, the type inferred for 'x' is number and the type inferred for 's' is string.
17691799 function getWidenedTypeForVariableDeclaration(declaration: VariableDeclaration, reportErrors?: boolean): Type {
17701800 var type = getTypeForVariableDeclaration(declaration);
17711801 if (type) {
17721802 if (reportErrors) {
17731803 reportErrorsFromWidening(declaration, type);
17741804 }
1805+ // During a normal type check we'll never get to here with a property assignment (the check of the containing
1806+ // object literal uses a different path). We exclude widening only so that language services and type verification
1807+ // tools see the actual type.
17751808 return declaration.kind !== SyntaxKind.PropertyAssignment ? getWidenedType(type) : type;
17761809 }
1810+ // If no type was specified and nothing could be inferred, and if the declaration specifies a binding pattern, use
1811+ // the type implied by the binding pattern
17771812 if (isBindingPattern(declaration.name)) {
17781813 return getTypeFromBindingPattern(<BindingPattern>declaration.name);
17791814 }
@@ -4052,7 +4087,7 @@ module ts {
40524087 return type.flags & TypeFlags.Reference && (<TypeReference>type).target === globalArrayType;
40534088 }
40544089
4055- function isTupleType ( type : Type ) : boolean {
4090+ function isTupleLikeType (type: Type): boolean {
40564091 return !!getPropertyOfType(type, "0");
40574092 }
40584093
@@ -4890,9 +4925,10 @@ module ts {
48904925 }
48914926
48924927 // In a variable, parameter or property declaration with a type annotation, the contextual type of an initializer
4893- // expression is the type of the variable, parameter or property. In a parameter declaration of a contextually
4894- // typed function expression, the contextual type of an initializer expression is the contextual type of the
4895- // parameter.
4928+ // expression is the type of the variable, parameter or property. Otherwise, in a parameter declaration of a
4929+ // contextually typed function expression, the contextual type of an initializer expression is the contextual type
4930+ // of the parameter. Otherwise, in a variable or parameter declaration with a binding pattern name, the contextual
4931+ // type of an initializer expression is the type implied by the binding pattern.
48964932 function getContextualTypeForInitializerExpression(node: Expression): Type {
48974933 var declaration = <VariableOrParameterDeclaration>node.parent;
48984934 if (node === declaration.initializer) {
@@ -5001,8 +5037,8 @@ module ts {
50015037 }
50025038
50035039 // Return true if the given contextual type is a tuple-like type
5004- function contextualTypeIsTupleType ( type : Type ) : boolean {
5005- return ! ! ( type . flags & TypeFlags . Union ? forEach ( ( < UnionType > type ) . types , t => isTupleType ( t ) ) : isTupleType ( type ) ) ;
5040+ function contextualTypeIsTupleLikeType (type: Type): boolean {
5041+ return !!(type.flags & TypeFlags.Union ? forEach((<UnionType>type).types, t => isTupleLikeType (t)) : isTupleLikeType (type));
50065042 }
50075043
50085044 // Return true if the given contextual type provides an index signature of the given kind
@@ -5160,6 +5196,9 @@ module ts {
51605196 return mapper && mapper !== identityMapper;
51615197 }
51625198
5199+ // A node is an assignment target if it is on the left hand side of an '=' token, if it is parented by a property
5200+ // assignment in an object literal that is an assignment target, or if it is parented by an array literal that is
5201+ // an assignment target. Examples include 'a = xxx', '{ p: a } = xxx', '[{ p: a}] = xxx'.
51635202 function isAssignmentTarget(node: Node): boolean {
51645203 var parent = node.parent;
51655204 if (parent.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>parent).operator === SyntaxKind.EqualsToken && (<BinaryExpression>parent).left === node) {
@@ -5181,7 +5220,7 @@ module ts {
51815220 }
51825221 var elementTypes = map(elements, e => checkExpression(e, contextualMapper));
51835222 var contextualType = getContextualType(node);
5184- if ( ( contextualType && contextualTypeIsTupleType ( contextualType ) ) || isAssignmentTarget ( node ) ) {
5223+ if ((contextualType && contextualTypeIsTupleLikeType (contextualType)) || isAssignmentTarget(node)) {
51855224 return createTupleType(elementTypes);
51865225 }
51875226 return createArrayType(getUnionType(elementTypes));
@@ -6492,7 +6531,7 @@ module ts {
64926531 var p = properties[i];
64936532 if (p.kind === SyntaxKind.PropertyAssignment || p.kind === SyntaxKind.ShorthandPropertyAssignment) {
64946533 // TODO(andersh): Computed property support
6495- var name = < Identifier > ( ( < PropertyDeclaration > p ) . name ) ;
6534+ var name = <Identifier>(<PropertyDeclaration>p).name;
64966535 var type = sourceType.flags & TypeFlags.Any ? sourceType :
64976536 getTypeOfPropertyOfType(sourceType, name.text) ||
64986537 isNumericName(name.text) && getIndexTypeOfType(sourceType, IndexKind.Number) ||
@@ -6523,7 +6562,7 @@ module ts {
65236562 if (e.kind !== SyntaxKind.OmittedExpression) {
65246563 var propName = "" + i;
65256564 var type = sourceType.flags & TypeFlags.Any ? sourceType :
6526- isTupleType ( sourceType ) ? getTypeOfPropertyOfType ( sourceType , propName ) :
6565+ isTupleLikeType (sourceType) ? getTypeOfPropertyOfType(sourceType, propName) :
65276566 getIndexTypeOfType(sourceType, IndexKind.Number);
65286567 if (type) {
65296568 checkDestructuringAssignment(e, type, contextualMapper);
0 commit comments