@@ -2406,7 +2406,7 @@ namespace ts {
24062406
24072407 // If the declaration specifies a binding pattern, use the type implied by the binding pattern
24082408 if (isBindingPattern(declaration.name)) {
2409- return getTypeFromBindingPattern(<BindingPattern>declaration.name);
2409+ return getTypeFromBindingPattern(<BindingPattern>declaration.name, /*includePatternInType*/ false );
24102410 }
24112411
24122412 // No type specified and nothing can be inferred
@@ -2421,13 +2421,13 @@ namespace ts {
24212421 return getWidenedType(checkExpressionCached(element.initializer));
24222422 }
24232423 if (isBindingPattern(element.name)) {
2424- return getTypeFromBindingPattern(<BindingPattern>element.name);
2424+ return getTypeFromBindingPattern(<BindingPattern>element.name, /*includePatternInType*/ false );
24252425 }
24262426 return anyType;
24272427 }
24282428
24292429 // Return the type implied by an object binding pattern
2430- function getTypeFromObjectBindingPattern(pattern: BindingPattern): Type {
2430+ function getTypeFromObjectBindingPattern(pattern: BindingPattern, includePatternInType: boolean ): Type {
24312431 let members: SymbolTable = {};
24322432 forEach(pattern.elements, e => {
24332433 let flags = SymbolFlags.Property | SymbolFlags.Transient | (e.initializer ? SymbolFlags.Optional : 0);
@@ -2436,28 +2436,27 @@ namespace ts {
24362436 symbol.type = getTypeFromBindingElement(e);
24372437 members[symbol.name] = symbol;
24382438 });
2439- return createAnonymousType(undefined, members, emptyArray, emptyArray, undefined, undefined);
2439+ let result = createAnonymousType(undefined, members, emptyArray, emptyArray, undefined, undefined);
2440+ if (includePatternInType) {
2441+ result.pattern = pattern;
2442+ }
2443+ return result;
24402444 }
24412445
24422446 // Return the type implied by an array binding pattern
2443- function getTypeFromArrayBindingPattern(pattern: BindingPattern): Type {
2444- let hasSpreadElement: boolean = false;
2445- let elementTypes: Type[] = [];
2446- forEach(pattern.elements, e => {
2447- elementTypes.push(e.kind === SyntaxKind.OmittedExpression || e.dotDotDotToken ? anyType : getTypeFromBindingElement(e));
2448- if (e.dotDotDotToken) {
2449- hasSpreadElement = true;
2450- }
2451- });
2452- if (!elementTypes.length) {
2447+ function getTypeFromArrayBindingPattern(pattern: BindingPattern, includePatternInType: boolean): Type {
2448+ let elements = pattern.elements;
2449+ if (elements.length === 0 || elements[elements.length - 1].dotDotDotToken) {
24532450 return languageVersion >= ScriptTarget.ES6 ? createIterableType(anyType) : anyArrayType;
24542451 }
2455- else if (hasSpreadElement) {
2456- let unionOfElements = getUnionType(elementTypes);
2457- return languageVersion >= ScriptTarget.ES6 ? createIterableType(unionOfElements) : createArrayType(unionOfElements);
2458- }
24592452 // If the pattern has at least one element, and no rest element, then it should imply a tuple type.
2460- return createTupleType(elementTypes);
2453+ let elementTypes = map(elements, e => e.kind === SyntaxKind.OmittedExpression ? anyType : getTypeFromBindingElement(e));
2454+ let result = createTupleType(elementTypes);
2455+ if (includePatternInType) {
2456+ result = clone(result);
2457+ result.pattern = pattern;
2458+ }
2459+ return result;
24612460 }
24622461
24632462 // Return the type implied by a binding pattern. This is the type implied purely by the binding pattern itself
@@ -2467,10 +2466,10 @@ namespace ts {
24672466 // used as the contextual type of an initializer associated with the binding pattern. Also, for a destructuring
24682467 // parameter with no type annotation or initializer, the type implied by the binding pattern becomes the type of
24692468 // the parameter.
2470- function getTypeFromBindingPattern(pattern: BindingPattern): Type {
2469+ function getTypeFromBindingPattern(pattern: BindingPattern, includePatternInType?: boolean ): Type {
24712470 return pattern.kind === SyntaxKind.ObjectBindingPattern
2472- ? getTypeFromObjectBindingPattern(pattern)
2473- : getTypeFromArrayBindingPattern(pattern);
2471+ ? getTypeFromObjectBindingPattern(pattern, includePatternInType )
2472+ : getTypeFromArrayBindingPattern(pattern, includePatternInType );
24742473 }
24752474
24762475 // Return the type associated with a variable, parameter, or property declaration. In the simple case this is the type
@@ -6606,18 +6605,12 @@ namespace ts {
66066605 }
66076606 }
66086607 if (isBindingPattern(declaration.name)) {
6609- return createImpliedType( getTypeFromBindingPattern(<BindingPattern>declaration.name) );
6608+ return getTypeFromBindingPattern(<BindingPattern>declaration.name, /*includePatternInType*/ true );
66106609 }
66116610 }
66126611 return undefined;
66136612 }
66146613
6615- function createImpliedType(type: Type): Type {
6616- var result = clone(type);
6617- result.flags |= TypeFlags.ImpliedType;
6618- return result;
6619- }
6620-
66216614 function getContextualTypeForReturnExpression(node: Expression): Type {
66226615 let func = getContainingFunction(node);
66236616 if (func && !func.asteriskToken) {
@@ -7044,17 +7037,28 @@ namespace ts {
70447037 // If array literal is actually a destructuring pattern, mark it as an implied type. We do this such
70457038 // that we get the same behavior for "var [x, y] = []" and "[x, y] = []".
70467039 if (inDestructuringPattern && elementTypes.length) {
7047- return createImpliedType(createTupleType(elementTypes));
7040+ let type = clone(createTupleType(elementTypes));
7041+ type.pattern = node;
7042+ return type;
70487043 }
70497044 let contextualType = getContextualType(node);
7050- let contextualTupleLikeType = contextualType && contextualTypeIsTupleLikeType(contextualType) ? contextualType : undefined;
7051- if (contextualTupleLikeType) {
7052- // If array literal is contextually typed by the implied type of a binding pattern, pad the resulting
7053- // tuple type with elements from the binding tuple type to make the lengths equal.
7054- if (contextualTupleLikeType.flags & TypeFlags.Tuple && contextualTupleLikeType.flags & TypeFlags.ImpliedType) {
7055- let contextualElementTypes = (<TupleType>contextualTupleLikeType).elementTypes;
7056- for (let i = elementTypes.length; i < contextualElementTypes.length; i++) {
7057- elementTypes.push(contextualElementTypes[i]);
7045+ if (contextualType && contextualTypeIsTupleLikeType(contextualType)) {
7046+ let pattern = contextualType.pattern;
7047+ // If array literal is contextually typed by a binding pattern or an assignment pattern,
7048+ // pad the resulting tuple type to make the lengths equal.
7049+ if (pattern && pattern.kind === SyntaxKind.ArrayBindingPattern) {
7050+ let bindingElements = (<BindingPattern>pattern).elements;
7051+ for (let i = elementTypes.length; i < bindingElements.length; i++) {
7052+ let hasDefaultValue = bindingElements[i].initializer;
7053+ elementTypes.push(hasDefaultValue ? (<TupleType>contextualType).elementTypes[i] : undefinedType);
7054+ }
7055+ }
7056+ else if (pattern && pattern.kind === SyntaxKind.ArrayLiteralExpression) {
7057+ let assignmentElements = (<ArrayLiteralExpression>pattern).elements;
7058+ for (let i = elementTypes.length; i < assignmentElements.length; i++) {
7059+ let hasDefaultValue = assignmentElements[i].kind === SyntaxKind.BinaryExpression &&
7060+ (<BinaryExpression>assignmentElements[i]).operatorToken.kind === SyntaxKind.EqualsToken;
7061+ elementTypes.push(hasDefaultValue ? (<TupleType>contextualType).elementTypes[i] : undefinedType);
70587062 }
70597063 }
70607064 if (elementTypes.length) {
@@ -7129,6 +7133,8 @@ namespace ts {
71297133 let propertiesTable: SymbolTable = {};
71307134 let propertiesArray: Symbol[] = [];
71317135 let contextualType = getContextualType(node);
7136+ let contextualTypeHasPattern = contextualType && contextualType.pattern &&
7137+ contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern;
71327138 let typeFlags: TypeFlags = 0;
71337139
71347140 for (let memberDecl of node.properties) {
@@ -7151,7 +7157,7 @@ namespace ts {
71517157 let prop = <TransientSymbol>createSymbol(SymbolFlags.Property | SymbolFlags.Transient | member.flags, member.name);
71527158 // If object literal is contextually typed by the implied type of a binding pattern, and if the
71537159 // binding pattern specifies a default value for the property, make the property optional.
7154- if (contextualType && contextualType.flags & TypeFlags.ImpliedType ) {
7160+ if (contextualTypeHasPattern ) {
71557161 let impliedProp = getPropertyOfType(contextualType, member.name);
71567162 if (impliedProp) {
71577163 prop.flags |= impliedProp.flags & SymbolFlags.Optional;
@@ -7185,7 +7191,7 @@ namespace ts {
71857191
71867192 // If object literal is contextually typed by the implied type of a binding pattern, augment the result
71877193 // type with those properties for which the binding pattern specifies a default value.
7188- if (contextualType && contextualType.flags & TypeFlags.ImpliedType ) {
7194+ if (contextualTypeHasPattern ) {
71897195 for (let prop of getPropertiesOfType(contextualType)) {
71907196 if (prop.flags & SymbolFlags.Optional && !hasProperty(propertiesTable, prop.name)) {
71917197 propertiesTable[prop.name] = prop;
0 commit comments