diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8b1b70b0fa1..22668d7b47c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1758,7 +1758,15 @@ namespace ts { return false; } - function isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): SymbolAccessibilityResult { + /** + * Check if the given symbol in given enclosing declaration is accessible and mark all associated alias to be visible if requested + * + * @param symbol a Symbol to check if accessible + * @param enclosingDeclaration a Node containing the symbol + * @param meaning a SymbolFlags to check if such meaning of the symbol is accessible + * @param shouldComputeAliasToMarkVisible 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 { if (symbol && enclosingDeclaration && !(symbol.flags & SymbolFlags.TypeParameter)) { const initialSymbol = symbol; let meaningToLook = meaning; @@ -1766,7 +1774,7 @@ namespace ts { // Symbol is accessible if it by itself is accessible const accessibleSymbolChain = getAccessibleSymbolChain(symbol, enclosingDeclaration, meaningToLook, /*useOnlyExternalAliasing*/ false); if (accessibleSymbolChain) { - const hasAccessibleDeclarations = hasVisibleDeclarations(accessibleSymbolChain[0]); + const hasAccessibleDeclarations = hasVisibleDeclarations(accessibleSymbolChain[0], shouldComputeAliasesToMakeVisible); if (!hasAccessibleDeclarations) { return { accessibility: SymbolAccessibility.NotAccessible, @@ -1830,7 +1838,7 @@ namespace ts { return isAmbientModule(declaration) || (declaration.kind === SyntaxKind.SourceFile && isExternalOrCommonJsModule(declaration)); } - function hasVisibleDeclarations(symbol: Symbol): SymbolVisibilityResult { + function hasVisibleDeclarations(symbol: Symbol, shouldComputeAliasToMarkVisible: boolean): SymbolVisibilityResult { let aliasesToMakeVisible: AnyImportSyntax[]; if (forEach(symbol.declarations, declaration => !getIsDeclarationVisible(declaration))) { return undefined; @@ -1846,14 +1854,16 @@ namespace ts { if (anyImportSyntax && !(getModifierFlags(anyImportSyntax) & ModifierFlags.Export) && // import clause without export isDeclarationVisible(anyImportSyntax.parent)) { - getNodeLinks(declaration).isVisible = true; - if (aliasesToMakeVisible) { - if (!contains(aliasesToMakeVisible, anyImportSyntax)) { - aliasesToMakeVisible.push(anyImportSyntax); + if (shouldComputeAliasToMarkVisible) { + getNodeLinks(declaration).isVisible = true; + if (aliasesToMakeVisible) { + if (!contains(aliasesToMakeVisible, anyImportSyntax)) { + aliasesToMakeVisible.push(anyImportSyntax); + } + } + else { + aliasesToMakeVisible = [anyImportSyntax]; } - } - else { - aliasesToMakeVisible = [anyImportSyntax]; } return true; } @@ -1888,7 +1898,7 @@ namespace ts { const symbol = resolveName(enclosingDeclaration, (firstIdentifier).text, meaning, /*nodeNotFoundErrorMessage*/ undefined, /*nameArg*/ undefined); // Verify if the symbol is accessible - return (symbol && hasVisibleDeclarations(symbol)) || { + return (symbol && hasVisibleDeclarations(symbol, /*shouldComputeAliasToMarkVisible*/ true)) || { accessibility: SymbolAccessibility.NotAccessible, errorSymbolName: getTextOfNode(firstIdentifier), errorNode: firstIdentifier @@ -2163,7 +2173,9 @@ namespace ts { // The specified symbol flags need to be reinterpreted as type flags buildSymbolDisplay(type.symbol, writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, nextFlags); } - else if (!(flags & TypeFormatFlags.InTypeAlias) && type.flags & (TypeFlags.Anonymous | TypeFlags.UnionOrIntersection) && type.aliasSymbol) { + else if (!(flags & TypeFormatFlags.InTypeAlias) && type.flags & (TypeFlags.Anonymous | TypeFlags.UnionOrIntersection) && type.aliasSymbol && + isSymbolAccessible(type.aliasSymbol, enclosingDeclaration, SymbolFlags.Type, /*shouldComputeAliasesToMakeVisible*/ false).accessibility === SymbolAccessibility.Accessible) { + // Only write out inferred type with its corresponding type-alias if type-alias is visible const typeArguments = type.aliasTypeArguments; writeSymbolTypeReference(type.aliasSymbol, typeArguments, 0, typeArguments ? typeArguments.length : 0, nextFlags); } diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index 68e488295e7..a015ad79b97 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -306,7 +306,7 @@ namespace ts { } function trackSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) { - handleSymbolAccessibilityError(resolver.isSymbolAccessible(symbol, enclosingDeclaration, meaning)); + handleSymbolAccessibilityError(resolver.isSymbolAccessible(symbol, enclosingDeclaration, meaning, /*shouldComputeAliasesToMakeVisible*/ true)); recordTypeReferenceDirectivesIfNecessary(resolver.getTypeReferenceDirectivesForSymbol(symbol, meaning)); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 82844980ca7..0c2a3dbd773 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2138,7 +2138,7 @@ namespace ts { writeReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void; writeTypeOfExpression(expr: Expression, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void; writeBaseConstructorTypeOfClass(node: ClassLikeDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void; - isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): SymbolAccessibilityResult; + isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags, shouldComputeAliasToMarkVisible: boolean): SymbolAccessibilityResult; isEntityNameVisible(entityName: EntityNameOrEntityNameExpression, enclosingDeclaration: Node): SymbolVisibilityResult; // Returns the constant value this property access resolves to, or 'undefined' for a non-constant getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): number;