From fdd1f30a955ea2aa99dea761754bb12ee52cc32b Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 15 Jul 2015 15:56:13 -0700 Subject: [PATCH] Enable retrieving the type of a binding property name when an initializer/type annotation is present. --- src/compiler/checker.ts | 19 ++++++++++++++----- src/services/services.ts | 15 +++++++++++++-- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8122ab3c983..38554f63b2a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2293,6 +2293,7 @@ namespace ts { if (declaration.parent.parent.kind === SyntaxKind.ForInStatement) { return anyType; } + if (declaration.parent.parent.kind === SyntaxKind.ForOfStatement) { // checkRightHandSideOfForOf will return undefined if the for-of expression type was // missing properties/signatures required to get its iteratedType (like @@ -2300,13 +2301,16 @@ namespace ts { // or it may have led to an error inside getElementTypeOfIterable. return checkRightHandSideOfForOf((declaration.parent.parent).expression) || anyType; } + if (isBindingPattern(declaration.parent)) { return getTypeForBindingElement(declaration); } + // Use type from type annotation if one is present if (declaration.type) { return getTypeFromTypeNode(declaration.type); } + if (declaration.kind === SyntaxKind.Parameter) { let func = declaration.parent; // For a parameter of a set accessor, use the type of the get accessor if one is present @@ -2322,14 +2326,22 @@ namespace ts { return type; } } + // Use the type of the initializer expression if one is present if (declaration.initializer) { return checkExpressionCached(declaration.initializer); } + // If it is a short-hand property assignment, use the type of the identifier if (declaration.kind === SyntaxKind.ShorthandPropertyAssignment) { return checkIdentifier(declaration.name); } + + // If the declaration specifies a binding pattern, use the type implied by the binding pattern + if (isBindingPattern(declaration.name)) { + return getTypeFromBindingPattern(declaration.name); + } + // No type specified and nothing can be inferred return undefined; } @@ -2415,13 +2427,10 @@ namespace ts { // tools see the actual type. return declaration.kind !== SyntaxKind.PropertyAssignment ? getWidenedType(type) : type; } - // If no type was specified and nothing could be inferred, and if the declaration specifies a binding pattern, use - // the type implied by the binding pattern - if (isBindingPattern(declaration.name)) { - return getTypeFromBindingPattern(declaration.name); - } + // Rest parameters default to type any[], other parameters default to type any type = declaration.dotDotDotToken ? anyArrayType : anyType; + // Report implicit any errors unless this is a private property within an ambient declaration if (reportErrors && compilerOptions.noImplicitAny) { let root = getRootDeclaration(declaration); diff --git a/src/services/services.ts b/src/services/services.ts index d79436bb478..0a34ed0e1c0 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -3232,8 +3232,19 @@ namespace ts { // We are *only* completing on properties from the type being destructured. isNewIdentifierLocation = false; - typeForObject = typeChecker.getTypeAtLocation(objectLikeContainer); - existingMembers = (objectLikeContainer).elements; + let rootDeclaration = getRootDeclaration(objectLikeContainer.parent); + if (isVariableLike(rootDeclaration)) { + // We don't want to complete using the type acquired by the shape + // of the binding pattern; we are only interested in types acquired + // through type declaration or inference. + if (rootDeclaration.initializer || rootDeclaration.type) { + typeForObject = typeChecker.getTypeAtLocation(objectLikeContainer); + existingMembers = (objectLikeContainer).elements; + } + } + else { + Debug.fail("Root declaration is not variable-like.") + } } else { Debug.fail("Expected object literal or binding pattern, got " + objectLikeContainer.kind);