diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index bb1fbbdd526..f3658c645db 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2424,12 +2424,15 @@ namespace ts { const visitedSymbolTables: SymbolTable[] = []; return forEachSymbolTableInScope(enclosingDeclaration, getAccessibleSymbolChainFromSymbolTable); - function getAccessibleSymbolChainFromSymbolTable(symbols: SymbolTable): Symbol[] | undefined { + /** + * @param {ignoreQualification} boolean Set when a symbol is being looked for through the exports of another symbol (meaning we have a route to qualify it already) + */ + function getAccessibleSymbolChainFromSymbolTable(symbols: SymbolTable, ignoreQualification?: boolean): Symbol[] | undefined { if (!pushIfUnique(visitedSymbolTables, symbols)) { return undefined; } - const result = trySymbolTable(symbols); + const result = trySymbolTable(symbols, ignoreQualification); visitedSymbolTables.pop(); return result; } @@ -2441,22 +2444,22 @@ namespace ts { !!getAccessibleSymbolChain(symbolFromSymbolTable.parent, enclosingDeclaration, getQualifiedLeftMeaning(meaning), useOnlyExternalAliasing); } - function isAccessible(symbolFromSymbolTable: Symbol, resolvedAliasSymbol?: Symbol) { + function isAccessible(symbolFromSymbolTable: Symbol, resolvedAliasSymbol?: Symbol, ignoreQualification?: boolean) { return symbol === (resolvedAliasSymbol || symbolFromSymbolTable) && // if the symbolFromSymbolTable is not external module (it could be if it was determined as ambient external module and would be in globals table) // and if symbolFromSymbolTable or alias resolution matches the symbol, // check the symbol can be qualified, it is only then this symbol is accessible !some(symbolFromSymbolTable.declarations, hasExternalModuleSymbol) && - canQualifySymbol(symbolFromSymbolTable, meaning); + (ignoreQualification || canQualifySymbol(symbolFromSymbolTable, meaning)); } function isUMDExportSymbol(symbol: Symbol) { return symbol && symbol.declarations && symbol.declarations[0] && isNamespaceExportDeclaration(symbol.declarations[0]); } - function trySymbolTable(symbols: SymbolTable) { + function trySymbolTable(symbols: SymbolTable, ignoreQualification: boolean | undefined) { // If symbol is directly available by its name in the symbol table - if (isAccessible(symbols.get(symbol.escapedName))) { + if (isAccessible(symbols.get(symbol.escapedName), /*resolvedAliasSymbol*/ undefined, ignoreQualification)) { return [symbol]; } @@ -2469,14 +2472,14 @@ namespace ts { && (!useOnlyExternalAliasing || some(symbolFromSymbolTable.declarations, isExternalModuleImportEqualsDeclaration))) { const resolvedImportedSymbol = resolveAlias(symbolFromSymbolTable); - if (isAccessible(symbolFromSymbolTable, resolvedImportedSymbol)) { + if (isAccessible(symbolFromSymbolTable, resolvedImportedSymbol, ignoreQualification)) { return [symbolFromSymbolTable]; } // Look in the exported members, if we can find accessibleSymbolChain, symbol is accessible using this chain // but only if the symbolFromSymbolTable can be qualified const candidateTable = getExportsOfSymbol(resolvedImportedSymbol); - const accessibleSymbolsFromExports = candidateTable && getAccessibleSymbolChainFromSymbolTable(candidateTable); + const accessibleSymbolsFromExports = candidateTable && getAccessibleSymbolChainFromSymbolTable(candidateTable, /*ignoreQualification*/ true); if (accessibleSymbolsFromExports && canQualifySymbol(symbolFromSymbolTable, getQualifiedLeftMeaning(meaning))) { return [symbolFromSymbolTable].concat(accessibleSymbolsFromExports); } diff --git a/tests/baselines/reference/moduleDeclarationExportStarShadowingGlobalIsNameable.js b/tests/baselines/reference/moduleDeclarationExportStarShadowingGlobalIsNameable.js new file mode 100644 index 00000000000..77b1b5f8ff4 --- /dev/null +++ b/tests/baselines/reference/moduleDeclarationExportStarShadowingGlobalIsNameable.js @@ -0,0 +1,60 @@ +//// [tests/cases/compiler/moduleDeclarationExportStarShadowingGlobalIsNameable.ts] //// + +//// [index.ts] +export * from "./account"; + +//// [account.ts] +export interface Account { + myAccNum: number; +} +interface Account2 { + myAccNum: number; +} +export { Account2 as Acc }; + +//// [index.ts] +declare global { + interface Account { + someProp: number; + } + interface Acc { + someProp: number; + } +} +import * as model from "./model"; +export const func = (account: model.Account, acc2: model.Acc) => {}; + + +//// [account.js] +"use strict"; +exports.__esModule = true; +//// [index.js] +"use strict"; +exports.__esModule = true; +//// [index.js] +"use strict"; +exports.__esModule = true; +exports.func = function (account, acc2) { }; + + +//// [account.d.ts] +export interface Account { + myAccNum: number; +} +interface Account2 { + myAccNum: number; +} +export { Account2 as Acc }; +//// [index.d.ts] +export * from "./account"; +//// [index.d.ts] +declare global { + interface Account { + someProp: number; + } + interface Acc { + someProp: number; + } +} +import * as model from "./model"; +export declare const func: (account: model.Account, acc2: model.Acc) => void; diff --git a/tests/baselines/reference/moduleDeclarationExportStarShadowingGlobalIsNameable.symbols b/tests/baselines/reference/moduleDeclarationExportStarShadowingGlobalIsNameable.symbols new file mode 100644 index 00000000000..add5fce7476 --- /dev/null +++ b/tests/baselines/reference/moduleDeclarationExportStarShadowingGlobalIsNameable.symbols @@ -0,0 +1,49 @@ +=== tests/cases/compiler/model/index.ts === +export * from "./account"; +No type information for this code. +No type information for this code.=== tests/cases/compiler/model/account.ts === +export interface Account { +>Account : Symbol(Account, Decl(account.ts, 0, 0)) + + myAccNum: number; +>myAccNum : Symbol(Account.myAccNum, Decl(account.ts, 0, 26)) +} +interface Account2 { +>Account2 : Symbol(Account2, Decl(account.ts, 2, 1)) + + myAccNum: number; +>myAccNum : Symbol(Account2.myAccNum, Decl(account.ts, 3, 20)) +} +export { Account2 as Acc }; +>Account2 : Symbol(Acc, Decl(account.ts, 6, 8)) +>Acc : Symbol(Acc, Decl(account.ts, 6, 8)) + +=== tests/cases/compiler/index.ts === +declare global { +>global : Symbol(global, Decl(index.ts, 0, 0)) + + interface Account { +>Account : Symbol(Account, Decl(index.ts, 0, 16)) + + someProp: number; +>someProp : Symbol(Account.someProp, Decl(index.ts, 1, 23)) + } + interface Acc { +>Acc : Symbol(Acc, Decl(index.ts, 3, 5)) + + someProp: number; +>someProp : Symbol(Acc.someProp, Decl(index.ts, 4, 19)) + } +} +import * as model from "./model"; +>model : Symbol(model, Decl(index.ts, 8, 6)) + +export const func = (account: model.Account, acc2: model.Acc) => {}; +>func : Symbol(func, Decl(index.ts, 9, 12)) +>account : Symbol(account, Decl(index.ts, 9, 21)) +>model : Symbol(model, Decl(index.ts, 8, 6)) +>Account : Symbol(model.Account, Decl(account.ts, 0, 0)) +>acc2 : Symbol(acc2, Decl(index.ts, 9, 44)) +>model : Symbol(model, Decl(index.ts, 8, 6)) +>Acc : Symbol(model.Acc, Decl(account.ts, 6, 8)) + diff --git a/tests/baselines/reference/moduleDeclarationExportStarShadowingGlobalIsNameable.types b/tests/baselines/reference/moduleDeclarationExportStarShadowingGlobalIsNameable.types new file mode 100644 index 00000000000..af27f7e3678 --- /dev/null +++ b/tests/baselines/reference/moduleDeclarationExportStarShadowingGlobalIsNameable.types @@ -0,0 +1,50 @@ +=== tests/cases/compiler/model/index.ts === +export * from "./account"; +No type information for this code. +No type information for this code.=== tests/cases/compiler/model/account.ts === +export interface Account { +>Account : Account + + myAccNum: number; +>myAccNum : number +} +interface Account2 { +>Account2 : Account2 + + myAccNum: number; +>myAccNum : number +} +export { Account2 as Acc }; +>Account2 : any +>Acc : any + +=== tests/cases/compiler/index.ts === +declare global { +>global : any + + interface Account { +>Account : Account + + someProp: number; +>someProp : number + } + interface Acc { +>Acc : Acc + + someProp: number; +>someProp : number + } +} +import * as model from "./model"; +>model : typeof model + +export const func = (account: model.Account, acc2: model.Acc) => {}; +>func : (account: model.Account, acc2: model.Acc) => void +>(account: model.Account, acc2: model.Acc) => {} : (account: model.Account, acc2: model.Acc) => void +>account : model.Account +>model : any +>Account : model.Account +>acc2 : model.Acc +>model : any +>Acc : model.Acc + diff --git a/tests/cases/compiler/moduleDeclarationExportStarShadowingGlobalIsNameable.ts b/tests/cases/compiler/moduleDeclarationExportStarShadowingGlobalIsNameable.ts new file mode 100644 index 00000000000..9113e6e329b --- /dev/null +++ b/tests/cases/compiler/moduleDeclarationExportStarShadowingGlobalIsNameable.ts @@ -0,0 +1,24 @@ +// @declaration: true +// @filename: model/index.ts +export * from "./account"; + +// @filename: model/account.ts +export interface Account { + myAccNum: number; +} +interface Account2 { + myAccNum: number; +} +export { Account2 as Acc }; + +// @filename: index.ts +declare global { + interface Account { + someProp: number; + } + interface Acc { + someProp: number; + } +} +import * as model from "./model"; +export const func = (account: model.Account, acc2: model.Acc) => {};