diff --git a/src/services/symbolDisplay.ts b/src/services/symbolDisplay.ts index 03b2b59193621..4f2b6d0e77092 100644 --- a/src/services/symbolDisplay.ts +++ b/src/services/symbolDisplay.ts @@ -57,6 +57,7 @@ import { isNameOfFunctionDeclaration, isNewExpressionTarget, isObjectBindingPattern, + isOptionalChain, isTaggedTemplateExpression, isThisInTypeQuery, isTransientSymbol, @@ -322,6 +323,12 @@ function getSymbolDisplayPartsDocumentationAndSymbolKindWorker( let signature: Signature | undefined; type ??= isThisExpression ? typeChecker.getTypeAtLocation(location) : typeChecker.getTypeOfSymbolAtLocation(symbol, location); + // For optional symbols, use the non-optional type to avoid showing both '?' and '| undefined' + // but only when not in optional chaining contexts where '| undefined' is semantically meaningful + if (symbol.flags & SymbolFlags.Optional && type && !isOptionalChain(location)) { + type = typeChecker.getNonOptionalType(type); + } + if (location.parent && location.parent.kind === SyntaxKind.PropertyAccessExpression) { const right = (location.parent as PropertyAccessExpression).name; // Either the location is on the right of a property access, or on the left and the right is missing diff --git a/tests/cases/fourslash/quickInfoOptionalPropertyConsistency.ts b/tests/cases/fourslash/quickInfoOptionalPropertyConsistency.ts new file mode 100644 index 0000000000000..023758f50ef69 --- /dev/null +++ b/tests/cases/fourslash/quickInfoOptionalPropertyConsistency.ts @@ -0,0 +1,28 @@ +/// + +//// interface Options { +//// width?: number; +//// height?: number; +//// color?: ColorOptions; +//// border?: BorderOptions; +//// } +//// +//// interface ColorOptions { +//// primary: string; +//// secondary: string; +//// } +//// +//// interface BorderOptions { +//// style: string; +//// width: number; +//// } +//// +//// function processOptions(options: Options) { +//// return options.wi/*1*/dth + options.he/*2*/ight + options.co/*3*/lor + options.bo/*4*/rder; +//// } + +// Test that optional properties show consistently with '?' and not '| undefined' +verify.quickInfoAt("1", "(property) Options.width?: number"); +verify.quickInfoAt("2", "(property) Options.height?: number"); +verify.quickInfoAt("3", "(property) Options.color?: ColorOptions"); +verify.quickInfoAt("4", "(property) Options.border?: BorderOptions"); \ No newline at end of file