diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 76f9722342aaa..4c9446eee1139 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2680,8 +2680,8 @@ namespace ts { return false; } - function isTypeSymbolAccessible(typeSymbol: Symbol, enclosingDeclaration: Node): boolean { - const access = isSymbolAccessible(typeSymbol, enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/ false); + function isTypeSymbolAccessible(typeSymbol: Symbol, enclosingDeclaration: Node, acceptLocal = false): boolean { + const access = isSymbolAccessible(typeSymbol, enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/ false, acceptLocal); return access.accessibility === SymbolAccessibility.Accessible; } @@ -2698,7 +2698,7 @@ namespace ts { * @param meaning a SymbolFlags to check if such meaning of the symbol is accessible * @param shouldComputeAliasToMakeVisible a boolean value to indicate whether to return aliases to be mark visible in case the symbol is accessible */ - function isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags, shouldComputeAliasesToMakeVisible: boolean): SymbolAccessibilityResult { + function isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags, shouldComputeAliasesToMakeVisible: boolean, acceptLocal = false): SymbolAccessibilityResult { if (symbol && enclosingDeclaration && !(symbol.flags & SymbolFlags.TypeParameter)) { const initialSymbol = symbol; let meaningToLook = meaning; @@ -2708,6 +2708,11 @@ namespace ts { if (accessibleSymbolChain) { const hasAccessibleDeclarations = hasVisibleDeclarations(accessibleSymbolChain[0], shouldComputeAliasesToMakeVisible); if (!hasAccessibleDeclarations) { + if (acceptLocal) { + return { + accessibility: SymbolAccessibility.Accessible, + }; + } return { accessibility: SymbolAccessibility.NotAccessible, errorSymbolName: symbolToString(initialSymbol, enclosingDeclaration, meaning), @@ -3069,7 +3074,8 @@ namespace ts { // Ignore constraint/default when creating a usage (as opposed to declaration) of a type parameter. return createTypeReferenceNode(name, /*typeArguments*/ undefined); } - if (!inTypeAlias && type.aliasSymbol && (context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope || isTypeSymbolAccessible(type.aliasSymbol, context.enclosingDeclaration))) { + if (!inTypeAlias && type.aliasSymbol && (context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope || + isTypeSymbolAccessible(type.aliasSymbol, context.enclosingDeclaration, !!(context.flags & NodeBuilderFlags.UseLocalAliases)))) { const name = symbolToTypeReferenceName(type.aliasSymbol); const typeArgumentNodes = mapToTypeNodes(type.aliasTypeArguments, context); return createTypeReferenceNode(name, typeArgumentNodes); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 06f15e1d77a50..2fe5fa9562407 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3016,7 +3016,7 @@ namespace ts { WriteArrayAsGenericType = 1 << 1, // Write Array instead T[] // empty space UseStructuralFallback = 1 << 3, // When an alias cannot be named by its symbol, rather than report an error, fallback to a structural printout if possible - // empty space + UseLocalAliases = 1 << 4, // Write aliases that are in scope locally even if they are not exported. WriteTypeArgumentsOfSignature = 1 << 5, // Write the type arguments instead of type parameters of the signature UseFullyQualifiedType = 1 << 6, // Write out the fully qualified type name (eg. Module.Type, instead of Type) UseOnlyExternalAliasing = 1 << 7, // Only use external aliases for a symbol @@ -3053,7 +3053,7 @@ namespace ts { WriteArrayAsGenericType = 1 << 1, // Write Array instead T[] // hole because there's a hole in node builder flags UseStructuralFallback = 1 << 3, // When an alias cannot be named by its symbol, rather than report an error, fallback to a structural printout if possible - // hole because there's a hole in node builder flags + UseLocalAliases = 1 << 4, // Write aliases that are in scope locally even if they are not exported. WriteTypeArgumentsOfSignature = 1 << 5, // Write the type arguments instead of type parameters of the signature UseFullyQualifiedType = 1 << 6, // Write out the fully qualified type name (eg. Module.Type, instead of Type) // hole because `UseOnlyExternalAliasing` is here in node builder flags, but functions which take old flags use `SymbolFormatFlags` instead @@ -3084,7 +3084,7 @@ namespace ts { NodeBuilderFlagsMask = NoTruncation | WriteArrayAsGenericType | UseStructuralFallback | WriteTypeArgumentsOfSignature | UseFullyQualifiedType | SuppressAnyReturnType | MultilineObjectLiterals | WriteClassExpressionAsTypeLiteral | - UseTypeOfFunction | OmitParameterModifiers | UseAliasDefinedOutsideCurrentScope | AllowUniqueESSymbolType | InTypeAlias, + UseTypeOfFunction | OmitParameterModifiers | UseAliasDefinedOutsideCurrentScope | AllowUniqueESSymbolType | InTypeAlias | UseLocalAliases, } export const enum SymbolFormatFlags { diff --git a/src/services/utilities.ts b/src/services/utilities.ts index cd87824e7d682..6bb717466d2e6 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -1385,7 +1385,7 @@ namespace ts { export function typeToDisplayParts(typechecker: TypeChecker, type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): SymbolDisplayPart[] { return mapToDisplayParts(writer => { - typechecker.writeType(type, enclosingDeclaration, flags | TypeFormatFlags.MultilineObjectLiterals, writer); + typechecker.writeType(type, enclosingDeclaration, flags | TypeFormatFlags.MultilineObjectLiterals | TypeFormatFlags.UseLocalAliases, writer); }); } @@ -1396,7 +1396,7 @@ namespace ts { } export function signatureToDisplayParts(typechecker: TypeChecker, signature: Signature, enclosingDeclaration?: Node, flags?: TypeFormatFlags): SymbolDisplayPart[] { - flags |= TypeFormatFlags.UseAliasDefinedOutsideCurrentScope | TypeFormatFlags.MultilineObjectLiterals | TypeFormatFlags.WriteTypeArgumentsOfSignature | TypeFormatFlags.OmitParameterModifiers; + flags |= TypeFormatFlags.UseAliasDefinedOutsideCurrentScope | TypeFormatFlags.UseLocalAliases | TypeFormatFlags.MultilineObjectLiterals | TypeFormatFlags.WriteTypeArgumentsOfSignature | TypeFormatFlags.OmitParameterModifiers; return mapToDisplayParts(writer => { typechecker.writeSignature(signature, enclosingDeclaration, flags, /*signatureKind*/ undefined, writer); }); diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 9bd2de6aa41d2..a38544ace3af1 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -1848,6 +1848,7 @@ declare namespace ts { NoTruncation = 1, WriteArrayAsGenericType = 2, UseStructuralFallback = 8, + UseLocalAliases = 16, WriteTypeArgumentsOfSignature = 32, UseFullyQualifiedType = 64, UseOnlyExternalAliasing = 128, @@ -1876,6 +1877,7 @@ declare namespace ts { NoTruncation = 1, WriteArrayAsGenericType = 2, UseStructuralFallback = 8, + UseLocalAliases = 16, WriteTypeArgumentsOfSignature = 32, UseFullyQualifiedType = 64, SuppressAnyReturnType = 256, @@ -1892,7 +1894,7 @@ declare namespace ts { InFirstTypeArgument = 4194304, InTypeAlias = 8388608, /** @deprecated */ WriteOwnNameForAnyLike = 0, - NodeBuilderFlagsMask = 9469291 + NodeBuilderFlagsMask = 9469307 } enum SymbolFormatFlags { None = 0, diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 3c47002061ffc..9c6a8b2b3c486 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -1848,6 +1848,7 @@ declare namespace ts { NoTruncation = 1, WriteArrayAsGenericType = 2, UseStructuralFallback = 8, + UseLocalAliases = 16, WriteTypeArgumentsOfSignature = 32, UseFullyQualifiedType = 64, UseOnlyExternalAliasing = 128, @@ -1876,6 +1877,7 @@ declare namespace ts { NoTruncation = 1, WriteArrayAsGenericType = 2, UseStructuralFallback = 8, + UseLocalAliases = 16, WriteTypeArgumentsOfSignature = 32, UseFullyQualifiedType = 64, SuppressAnyReturnType = 256, @@ -1892,7 +1894,7 @@ declare namespace ts { InFirstTypeArgument = 4194304, InTypeAlias = 8388608, /** @deprecated */ WriteOwnNameForAnyLike = 0, - NodeBuilderFlagsMask = 9469291 + NodeBuilderFlagsMask = 9469307 } enum SymbolFormatFlags { None = 0, diff --git a/tests/cases/fourslash/quickInfoLocalTypeAliases.ts b/tests/cases/fourslash/quickInfoLocalTypeAliases.ts new file mode 100644 index 0000000000000..5bb7072017847 --- /dev/null +++ b/tests/cases/fourslash/quickInfoLocalTypeAliases.ts @@ -0,0 +1,35 @@ +/// + +// @Filename: fileA.ts +//// type LocalAlias = {a: T} +//// const var/*0*/1: LocalAlias +//// export type ExpAlias = {b: T} +//// const var/*1*/2: ExpAlias +//// export declare function doSomething(arg: T): ExpAlias + +// @Filename: fileB.ts +//// import { doSomething, ExpAlias } from "./fileA"; +//// type FileBAlias = {c: T} +//// declare const fba: FileBAlias +//// const res/*2*/ult = doSomething(fba); + +// @Filename: GH18754.ts +//// import "nothing" +//// type A/*3*/A = { tag: 'a', p/*4*/a: AL/*5*/L} +//// type BB = { tag: 'b', pb: ALL} +//// type ALL = AA | BB +//// declare var b/*6*/b: B/*7*/B +//// declare let a/*8*/ll: A/*9*/LL + +verify.quickInfos({ + 0: "const var1: LocalAlias", + 1: "const var2: ExpAlias", + 2: "const result: ExpAlias>", + 3: 'type AA = {\n tag: "a";\n pa: ALL;\n}', + 4: "(property) pa: ALL", + 5: "type ALL = AA | BB", + 6: "var bb: BB", + 7: 'type BB = {\n tag: "b";\n pb: ALL;\n}', + 8: "let all: ALL", + 9: "type ALL = AA | BB", +});