diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 2682a5938d1..9ce8b4f4eda 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1444,10 +1444,7 @@ namespace ts { // If this is a property-parameter, then also declare the property symbol into the // containing class. - if (node.flags & NodeFlags.AccessibilityModifier && - node.parent.kind === SyntaxKind.Constructor && - isClassLike(node.parent.parent)) { - + if (isPropertyParameterDeclaration(node)) { const classDeclaration = node.parent.parent; declareSymbol(classDeclaration.symbol.members, classDeclaration.symbol, node, SymbolFlags.Property, SymbolFlags.PropertyExcludes); } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7d4bfb43de7..57c4353baf1 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -67,6 +67,7 @@ namespace ts { // The language service will always care about the narrowed type of a symbol, because that is // the type the language says the symbol should have. getTypeOfSymbolAtLocation: getNarrowedTypeOfSymbol, + getSymbolOfParameterPropertyDeclaration, getDeclaredTypeOfSymbol, getPropertiesOfType, getPropertyOfType, @@ -427,6 +428,16 @@ namespace ts { } // return undefined if we can't find a symbol. } + + function getSymbolOfParameterPropertyDeclaration(parameter: ParameterDeclaration, parameterName: string): Symbol[] { + const constructoDeclaration = parameter.parent; + const classDeclaration = parameter.parent.parent; + + const parameterSymbol = getSymbol(constructoDeclaration.locals, parameterName, SymbolFlags.Value); + const propertySymbol = getSymbol(classDeclaration.symbol.members, parameterName, SymbolFlags.Value); + + return parameterSymbol && propertySymbol ? [parameterSymbol, propertySymbol] : undefined; + } function isBlockScopedNameDeclaredBeforeUse(declaration: Declaration, usage: Node): boolean { const declarationFile = getSourceFileOfNode(declaration); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index ff8ffa4ebd2..4c1fb2bb1cd 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1723,6 +1723,7 @@ namespace ts { getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[]; getSymbolAtLocation(node: Node): Symbol; + getSymbolOfParameterPropertyDeclaration(parameter: ParameterDeclaration, parameterName: string): Symbol[]; getShorthandAssignmentValueSymbol(location: Node): Symbol; getTypeAtLocation(node: Node): Type; typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index eee09fc641f..472225d31e5 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -2741,4 +2741,10 @@ namespace ts { } } } + + export function isPropertyParameterDeclaration(node: ParameterDeclaration): boolean { + // If this is a property-parameter, then also declare the property symbol into the + // containing class. + return node.flags & NodeFlags.AccessibilityModifier && node.parent.kind === SyntaxKind.Constructor && isClassLike(node.parent.parent); + } } diff --git a/src/services/services.ts b/src/services/services.ts index a9dda549ead..4f2af5c35c4 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -5967,6 +5967,15 @@ namespace ts { } } + // If the symbol.valueDeclaration is a property parameter declaration, + // we should include both parameter declaration symbol and property declaration symbol + // Parameter Declaration symbol is only visible within function scope, so the symbol is stored in contructor.locals. + // Property Declaration symbol is a member of the class, so the symbol is stored in its class Declaration.symbol.members + if (symbol.valueDeclaration && symbol.valueDeclaration.kind === SyntaxKind.Parameter && + isPropertyParameterDeclaration(symbol.valueDeclaration)) { + result = result.concat(typeChecker.getSymbolOfParameterPropertyDeclaration(symbol.valueDeclaration, symbol.name)); + } + // If this is a union property, add all the symbols from all its source symbols in all unioned types. // If the symbol is an instantiation from a another symbol (e.g. widened symbol) , add the root the list forEach(typeChecker.getRootSymbols(symbol), rootSymbol => { @@ -6036,6 +6045,8 @@ namespace ts { }); } + // If the reference + // Unwrap symbols to get to the root (e.g. transient symbols as a result of widening) // Or a union property, use its underlying unioned symbols return forEach(typeChecker.getRootSymbols(referenceSymbol), rootSymbol => {