diff --git a/src/services/symbolDisplay.ts b/src/services/symbolDisplay.ts index 6a5ab9a8b0d..e77a2647f48 100644 --- a/src/services/symbolDisplay.ts +++ b/src/services/symbolDisplay.ts @@ -254,10 +254,8 @@ export interface SymbolDisplayPartsDocumentationAndSymbolKind { tags: JSDocTagInfo[] | undefined; } -// TODO(drosen): Currently completion entry details passes the SemanticMeaning.All instead of using semanticMeaning of location -/** @internal */ -export function getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker: TypeChecker, symbol: Symbol, sourceFile: SourceFile, enclosingDeclaration: Node | undefined, - location: Node, semanticMeaning = getMeaningFromLocation(location), alias?: Symbol): SymbolDisplayPartsDocumentationAndSymbolKind { +function getSymbolDisplayPartsDocumentationAndSymbolKindWorker(typeChecker: TypeChecker, symbol: Symbol, sourceFile: SourceFile, enclosingDeclaration: Node | undefined, + location: Node, type: Type | undefined, semanticMeaning: SemanticMeaning, alias?: Symbol): SymbolDisplayPartsDocumentationAndSymbolKind { const displayParts: SymbolDisplayPart[] = []; let documentation: SymbolDisplayPart[] = []; let tags: JSDocTagInfo[] = []; @@ -265,7 +263,6 @@ export function getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker: Typ let symbolKind = semanticMeaning & SemanticMeaning.Value ? getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(typeChecker, symbol, location) : ScriptElementKind.unknown; let hasAddedSymbolInfo = false; const isThisExpression = location.kind === SyntaxKind.ThisKeyword && isInExpressionContext(location) || isThisInTypeQuery(location); - let type: Type | undefined; let documentationFromAlias: SymbolDisplayPart[] | undefined; let tagsFromAlias: JSDocTagInfo[] | undefined; let hasMultipleSignatures = false; @@ -300,7 +297,7 @@ export function getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker: Typ } let signature: Signature | undefined; - type = isThisExpression ? typeChecker.getTypeAtLocation(location) : typeChecker.getTypeOfSymbolAtLocation(symbol, location); + type ??= isThisExpression ? typeChecker.getTypeAtLocation(location) : typeChecker.getTypeOfSymbolAtLocation(symbol, location); if (location.parent && location.parent.kind === SyntaxKind.PropertyAccessExpression) { const right = (location.parent as PropertyAccessExpression).name; @@ -553,12 +550,13 @@ export function getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker: Typ isModuleWithStringLiteralName(resolvedNode) && hasSyntacticModifier(resolvedNode, ModifierFlags.Ambient); const shouldUseAliasName = symbol.name !== "default" && !isExternalModuleDeclaration; - const resolvedInfo = getSymbolDisplayPartsDocumentationAndSymbolKind( + const resolvedInfo = getSymbolDisplayPartsDocumentationAndSymbolKindWorker( typeChecker, resolvedSymbol, getSourceFileOfNode(resolvedNode), resolvedNode, declarationName, + type, semanticMeaning, shouldUseAliasName ? symbol : resolvedSymbol); displayParts.push(...resolvedInfo.displayParts); @@ -858,6 +856,13 @@ export function getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker: Typ } } +// TODO(drosen): Currently completion entry details passes the SemanticMeaning.All instead of using semanticMeaning of location +/** @internal */ +export function getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker: TypeChecker, symbol: Symbol, sourceFile: SourceFile, enclosingDeclaration: Node | undefined, + location: Node, semanticMeaning = getMeaningFromLocation(location), alias?: Symbol): SymbolDisplayPartsDocumentationAndSymbolKind { + return getSymbolDisplayPartsDocumentationAndSymbolKindWorker(typeChecker, symbol, sourceFile, enclosingDeclaration, location, /*type*/ undefined, semanticMeaning, alias); +} + function isLocalVariableOrFunction(symbol: Symbol) { if (symbol.parent) { return false; // This is exported symbol diff --git a/tests/cases/fourslash/quickInfoNarrowedTypeOfAliasSymbol.ts b/tests/cases/fourslash/quickInfoNarrowedTypeOfAliasSymbol.ts new file mode 100644 index 00000000000..1fefffac439 --- /dev/null +++ b/tests/cases/fourslash/quickInfoNarrowedTypeOfAliasSymbol.ts @@ -0,0 +1,17 @@ +/// +// @strict: true + +// @Filename: modules.ts +//// export declare const someEnv: string | undefined; + +// @Filename: app.ts +//// import { someEnv } from "./modules"; +//// declare function isString(v: any): v is string; +//// +//// if (isString(someEnv)) { +//// someEnv/*1*/.charAt(0); +//// } + +goTo.file("app.ts"); +goTo.marker("1"); +verify.quickInfoIs(`(alias) const someEnv: string\nimport someEnv`);